import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'

// ── Types ────────────────────────────────────────────────────────────────────

interface ContactSubmission {
  id: string
  submittedAt: string
  name: string
  email: string
  message: string
  messageType: string
  subscribe: boolean
  archived?: boolean
  source?: string
  inboundTo?: string
  notes?: string
}

interface Contact {
  key: string
  email: string
  name: string
  source: string | undefined
  inboundTo: string | undefined
  subscribe: boolean
  archived: boolean
  submittedAt: string
  message: string
  notes: string
  submissionCount: number
  mainId: string
  allIds: string[]
}

// ── Auth Shell ───────────────────────────────────────────────────────────────

export default function ContactsShell() {
  const [authState, setAuthState] = useState<'checking' | 'needs-password' | 'needs-totp' | 'ok'>('checking')
  const [password, setPassword] = useState('')
  const [totp, setTotp] = useState('')
  const [authError, setAuthError] = useState('')
  const [authBusy, setAuthBusy] = useState(false)

  useEffect(() => {
    fetch('/api/admin-auth/status', { credentials: 'include' })
      .then(r => r.json())
      .then((data: { authenticated?: boolean }) => {
        setAuthState(data.authenticated ? 'ok' : 'needs-password')
      })
      .catch(() => setAuthState('needs-password'))
  }, [])

  async function handleLogin(e: React.FormEvent) {
    e.preventDefault()
    setAuthBusy(true)
    setAuthError('')
    try {
      const res = await fetch('/api/admin-auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password }),
        credentials: 'include',
      })
      const data = await res.json() as { ok?: boolean; requiresTOTP?: boolean; message?: string }
      if (!res.ok) { setAuthError(data.message ?? 'Invalid password.'); setAuthBusy(false); return }
      if (data.requiresTOTP) { setAuthState('needs-totp'); setAuthBusy(false); return }
      setAuthState('ok')
    } catch { setAuthError('Login failed.') }
    setAuthBusy(false)
  }

  async function handleTotp(e: React.FormEvent) {
    e.preventDefault()
    setAuthBusy(true)
    setAuthError('')
    try {
      const res = await fetch('/api/admin-auth/totp', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token: totp }),
        credentials: 'include',
      })
      const data = await res.json() as { ok?: boolean; message?: string }
      if (!res.ok) { setAuthError(data.message ?? 'Invalid code.'); setAuthBusy(false); return }
      setAuthState('ok')
    } catch { setAuthError('Verification failed.') }
    setAuthBusy(false)
  }

  if (authState === 'checking') {
    return <div className="em-auth-loading">Loading…</div>
  }

  if (authState === 'needs-password') {
    return (
      <div className="em-auth-wrap">
        <form className="em-auth-form" onSubmit={handleLogin}>
          <h1 className="em-auth-title">Contacts</h1>
          <label className="em-auth-label">Admin password
            <input type="password" className="em-auth-input" value={password} onChange={e => setPassword(e.target.value)} autoFocus />
          </label>
          {authError && <p className="em-auth-error">{authError}</p>}
          <button type="submit" className="em-btn em-btn--primary" disabled={authBusy}>
            {authBusy ? 'Signing in…' : 'Sign in'}
          </button>
        </form>
      </div>
    )
  }

  if (authState === 'needs-totp') {
    return (
      <div className="em-auth-wrap">
        <form className="em-auth-form" onSubmit={handleTotp}>
          <h1 className="em-auth-title">Two-factor code</h1>
          <label className="em-auth-label">Authenticator code
            <input
              type="text"
              className="em-auth-input"
              inputMode="numeric"
              pattern="[0-9]*"
              maxLength={6}
              value={totp}
              onChange={e => setTotp(e.target.value)}
              autoFocus
            />
          </label>
          {authError && <p className="em-auth-error">{authError}</p>}
          <button type="submit" className="em-btn em-btn--primary" disabled={authBusy}>
            {authBusy ? 'Verifying…' : 'Verify'}
          </button>
        </form>
      </div>
    )
  }

  return <ContactsClient />
}

// ── Contacts Client ──────────────────────────────────────────────────────────

function ContactsClient() {
  const [submissions, setSubmissions] = useState<ContactSubmission[]>([])
  const [loading, setLoading] = useState(true)
  const [search, setSearch] = useState('')
  const [showArchived, setShowArchived] = useState(false)
  const [editingId, setEditingId] = useState<string | null>(null)
  const [editName, setEditName] = useState('')
  const [editNotes, setEditNotes] = useState('')
  const [editSaving, setEditSaving] = useState(false)
  const [addOpen, setAddOpen] = useState(false)
  const [addName, setAddName] = useState('')
  const [addEmail, setAddEmail] = useState('')
  const [addNotes, setAddNotes] = useState('')
  const [addBusy, setAddBusy] = useState(false)
  const [addError, setAddError] = useState('')

  const reload = useCallback(async () => {
    try {
      const res = await fetch('/api/admin-contact-submissions', { credentials: 'include' })
      if (res.ok) {
        const data = await res.json() as { submissions: ContactSubmission[] }
        setSubmissions(data.submissions ?? [])
      }
    } catch { /* silent */ }
    setLoading(false)
  }, [])

  useEffect(() => { reload() }, [reload])

  const contacts: Contact[] = useMemo(() => {
    const grouped = new Map<string, ContactSubmission[]>()
    for (const s of submissions) {
      const key = s.email?.trim().toLowerCase() || s.id
      const arr = grouped.get(key) ?? []
      arr.push(s)
      grouped.set(key, arr)
    }
    return Array.from(grouped.values())
      .map(entries => {
        const sorted = [...entries].sort((a, b) => new Date(b.submittedAt).getTime() - new Date(a.submittedAt).getTime())
        const latest = sorted[0]
        return {
          key: latest.email?.trim().toLowerCase() || latest.id,
          email: latest.email,
          name: latest.name,
          source: latest.source,
          inboundTo: latest.inboundTo,
          subscribe: sorted.some(s => s.subscribe),
          archived: sorted.every(s => s.archived === true),
          submittedAt: latest.submittedAt,
          message: latest.message || sorted.find(s => s.message)?.message || '',
          notes: latest.notes ?? '',
          submissionCount: sorted.length,
          mainId: latest.id,
          allIds: sorted.map(s => s.id),
        }
      })
      .sort((a, b) => new Date(b.submittedAt).getTime() - new Date(a.submittedAt).getTime())
  }, [submissions])

  const filtered = contacts.filter(c => {
    if (!showArchived && c.archived) return false
    if (!search.trim()) return true
    const q = search.toLowerCase()
    return (
      c.name.toLowerCase().includes(q) ||
      c.email.toLowerCase().includes(q) ||
      c.message.toLowerCase().includes(q) ||
      c.notes.toLowerCase().includes(q)
    )
  })

  function startEdit(c: Contact) {
    setEditingId(c.mainId)
    setEditName(c.name)
    setEditNotes(c.notes)
  }

  async function saveEdit() {
    if (!editingId) return
    setEditSaving(true)
    await fetch(`/api/admin-contact-submissions/${encodeURIComponent(editingId)}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ name: editName, notes: editNotes }),
    })
    setEditSaving(false)
    setEditingId(null)
    await reload()
  }

  async function deleteContact(c: Contact) {
    const label = c.name || c.email || 'this contact'
    const plural = c.submissionCount > 1 ? `all ${c.submissionCount} submissions` : 'submission'
    if (!confirm(`Delete ${plural} from ${label}?`)) return
    await Promise.all(
      c.allIds.map(id =>
        fetch(`/api/admin-contact-submissions/${encodeURIComponent(id)}`, {
          method: 'DELETE',
          credentials: 'include',
        })
      )
    )
    await reload()
  }

  async function handleAdd(e: React.FormEvent) {
    e.preventDefault()
    setAddBusy(true)
    setAddError('')
    try {
      const res = await fetch('/api/admin-contact-submissions/add', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ name: addName, email: addEmail, notes: addNotes }),
      })
      const data = await res.json() as { ok?: boolean; message?: string }
      if (!res.ok) { setAddError(data.message ?? 'Failed to add contact.'); setAddBusy(false); return }
      setAddOpen(false)
      setAddName('')
      setAddEmail('')
      setAddNotes('')
      await reload()
    } catch { setAddError('Network error.') }
    setAddBusy(false)
  }

  function sourceBadge(source: string | undefined) {
    if (source === 'manual') return <span className="ct-badge ct-badge--manual">manual</span>
    if (source === 'inbound-email') return <span className="ct-badge ct-badge--email">email</span>
    if (source === 'download') return <span className="ct-badge ct-badge--download">download</span>
    return <span className="ct-badge ct-badge--form">form</span>
  }

  function fmtDate(iso: string) {
    try {
      return new Date(iso).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
    } catch { return '—' }
  }

  return (
    <div className="ct-app">
      <header className="ct-header">
        <div className="ct-header-brand">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
            <circle cx="9" cy="7" r="4" />
            <path d="M23 21v-2a4 4 0 0 0-3-3.87" />
            <path d="M16 3.13a4 4 0 0 1 0 7.75" />
          </svg>
          Contacts
          <span className="ct-header-count">{contacts.length}</span>
        </div>
        <div className="ct-header-actions">
          <button
            type="button"
            className="em-btn em-btn--secondary em-btn--sm"
            onClick={() => { setAddOpen(o => !o); setAddError('') }}
          >
            {addOpen ? 'Cancel' : '+ Add Contact'}
          </button>
          <Link to="/email" className="em-btn em-btn--ghost em-btn--sm">✉ Email</Link>
          <Link to="/calendar" className="em-btn em-btn--ghost em-btn--sm">Calendar</Link>
          <Link to="/admin" className="em-btn em-btn--ghost em-btn--sm">← Admin</Link>
        </div>
      </header>

      {addOpen && (
        <div className="ct-add-banner">
          <form className="ct-add-form" onSubmit={handleAdd}>
            <h3 className="ct-add-title">Add Contact</h3>
            <div className="ct-add-row">
              <label className="ct-add-label">
                Name
                <input
                  className="ct-input"
                  type="text"
                  placeholder="Full name"
                  value={addName}
                  onChange={e => setAddName(e.target.value)}
                  autoFocus
                />
              </label>
              <label className="ct-add-label">
                Email
                <input
                  className="ct-input"
                  type="email"
                  placeholder="email@example.com"
                  value={addEmail}
                  onChange={e => setAddEmail(e.target.value)}
                />
              </label>
            </div>
            <label className="ct-add-label ct-add-label--full">
              Notes
              <textarea
                className="ct-input ct-notes-input"
                placeholder="Notes (optional)"
                value={addNotes}
                onChange={e => setAddNotes(e.target.value)}
                rows={2}
              />
            </label>
            {addError && <p className="ct-error">{addError}</p>}
            <div className="ct-add-actions">
              <button type="submit" className="em-btn em-btn--primary em-btn--sm" disabled={addBusy}>
                {addBusy ? 'Adding…' : 'Add Contact'}
              </button>
            </div>
          </form>
        </div>
      )}

      <div className="ct-toolbar">
        <input
          type="search"
          className="ct-search"
          placeholder="Search name, email, message, or notes…"
          value={search}
          onChange={e => setSearch(e.target.value)}
        />
        <label className="ct-archived-toggle">
          <input
            type="checkbox"
            checked={showArchived}
            onChange={e => setShowArchived(e.target.checked)}
          />
          Show archived
        </label>
        <span className="ct-count-label">
          {filtered.length} contact{filtered.length !== 1 ? 's' : ''}
        </span>
      </div>

      <div className="ct-list">
        {loading && <p className="ct-empty">Loading contacts…</p>}
        {!loading && filtered.length === 0 && (
          <p className="ct-empty">
            {search ? 'No contacts match your search.' : 'No contacts yet. Add one above.'}
          </p>
        )}

        {filtered.map(c => (
          <div key={c.mainId} className={`ct-card${c.archived ? ' ct-card--archived' : ''}`}>
            <div className="ct-avatar" aria-hidden="true">
              {(c.name || c.email || '?').charAt(0).toUpperCase()}
            </div>

            <div className="ct-card-body">
              {editingId === c.mainId ? (
                <div className="ct-edit-form">
                  <div className="ct-edit-row">
                    <label className="ct-edit-label">
                      Name
                      <input
                        className="ct-input"
                        type="text"
                        value={editName}
                        onChange={e => setEditName(e.target.value)}
                        autoFocus
                      />
                    </label>
                  </div>
                  <label className="ct-edit-label">
                    Notes
                    <textarea
                      className="ct-input ct-notes-input"
                      rows={3}
                      value={editNotes}
                      onChange={e => setEditNotes(e.target.value)}
                      placeholder="Add a note about this contact…"
                    />
                  </label>
                  <div className="ct-edit-actions">
                    <button
                      type="button"
                      className="em-btn em-btn--primary em-btn--sm"
                      onClick={saveEdit}
                      disabled={editSaving}
                    >
                      {editSaving ? 'Saving…' : 'Save'}
                    </button>
                    <button
                      type="button"
                      className="em-btn em-btn--ghost em-btn--sm"
                      onClick={() => setEditingId(null)}
                    >
                      Cancel
                    </button>
                  </div>
                </div>
              ) : (
                <>
                  <div className="ct-card-top">
                    <span className="ct-card-name">{c.name || <em>No name</em>}</span>
                    {c.email && (
                      <a className="ct-card-email" href={`mailto:${c.email}`}>{c.email}</a>
                    )}
                    {sourceBadge(c.source)}
                    {c.subscribe && <span className="ct-badge ct-badge--sub">subscriber</span>}
                    {c.submissionCount > 1 && (
                      <span className="ct-count-badge">{c.submissionCount}</span>
                    )}
                  </div>
                  <p className={`ct-card-notes${!c.notes ? ' ct-card-notes--empty' : ''}`}>
                    {c.notes || 'No notes — click Edit to add'}
                  </p>
                  <div className="ct-card-bottom">
                    <span className="ct-card-date">{fmtDate(c.submittedAt)}</span>
                    {c.message && (
                      <span className="ct-card-preview">
                        {c.message.length > 90 ? c.message.slice(0, 90) + '…' : c.message}
                      </span>
                    )}
                  </div>
                </>
              )}
            </div>

            {editingId !== c.mainId && (
              <div className="ct-card-actions">
                <button
                  type="button"
                  className="em-btn em-btn--ghost em-btn--sm"
                  onClick={() => startEdit(c)}
                >
                  Edit
                </button>
                <button
                  type="button"
                  className="em-btn em-btn--danger em-btn--sm"
                  onClick={() => deleteContact(c)}
                >
                  Delete
                </button>
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  )
}
