import { useCallback, useMemo, useState } from 'react'
import { apiUrl } from '../../lib/apiOrigin'

const EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi

function normalizeEmail(e: string) {
  return e.trim().toLowerCase()
}

function extractEmailsFromCSVText(text: string) {
  const found = text.match(EMAIL_RE) || []
  return Array.from(new Set(found.map(normalizeEmail)))
}

function extractEmailsFromTextarea(text: string) {
  return Array.from(
    new Set(
      text
        .split(/\n|,|;|\t/)
        .map(normalizeEmail)
        .filter((x) => x && x.includes('@')),
    ),
  )
}

function downloadCSV(filename: string, rows: string[]) {
  const csvContent = 'data:text/csv;charset=utf-8,' + rows.map((r) => `"${r.replace(/"/g, '""')}"`).join('\n')
  const encodedUri = encodeURI(csvContent)
  const link = document.createElement('a')
  link.setAttribute('href', encodedUri)
  link.setAttribute('download', filename)
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

/**
 * Admin tool ported from `app/Views/emails/parent_email_extractor.php` (client-side compare; no jQuery DataTables).
 */
export function ParentEmailExtractorPage() {
  const defaultApi = useMemo(() => apiUrl('/api/emails'), [])
  const [apiUrlInput, setApiUrlInput] = useState(defaultApi)
  const [csvSummary, setCsvSummary] = useState('')
  const [compareSummary, setCompareSummary] = useState('')
  const [usersText, setUsersText] = useState('')
  const [parentsText, setParentsText] = useState('')
  const [csvEmails, setCsvEmails] = useState<Set<string>>(new Set())
  const [existed, setExisted] = useState<string[]>([])
  const [needToAdd, setNeedToAdd] = useState<{ email: string; source: string }[]>([])

  const usersEmails = useMemo(() => extractEmailsFromTextarea(usersText), [usersText])
  const parentsEmails = useMemo(() => extractEmailsFromTextarea(parentsText), [parentsText])

  const handleParseCsv = useCallback(async (file: File | undefined) => {
    if (!file) {
      window.alert('Please choose a CSV file.')
      return
    }
    const text = await file.text()
    const emails = extractEmailsFromCSVText(text)
    setCsvEmails(new Set(emails))
    setCsvSummary(`Found ${emails.length} unique emails in CSV.`)
  }, [])

  const handleFetchApi = useCallback(async () => {
    const url = apiUrlInput.trim()
    if (!url) {
      window.alert('Enter your /api/emails endpoint URL.')
      return
    }
    try {
      const res = await fetch(url)
      if (!res.ok) throw new Error(`HTTP ${res.status}`)
      const data = (await res.json()) as { users?: string[]; parents?: string[] }
      const users = (data.users ?? []).map(normalizeEmail).filter(Boolean)
      const parents = (data.parents ?? []).map(normalizeEmail).filter(Boolean)
      setUsersText(users.join('\n'))
      setParentsText(parents.join('\n'))
      window.alert(`Fetched ${users.length} users and ${parents.length} parents emails.`)
    } catch (e) {
      console.error(e)
      window.alert('Failed to fetch API. See console for details.')
    }
  }, [apiUrlInput])

  const handleCompare = useCallback(() => {
    const u = new Set(usersEmails)
    const p = new Set(parentsEmails)
    const dbSet = new Set([...u, ...p])

    const existedList = [...csvEmails].filter((e) => dbSet.has(e)).sort()
    const needEmails = [...dbSet].filter((e) => !csvEmails.has(e)).sort()
    const needRows = needEmails.map((e) => {
      const inUsers = u.has(e)
      const inParents = p.has(e)
      let source = ''
      if (inUsers && inParents) source = 'Users + Parents'
      else if (inUsers) source = 'Users'
      else if (inParents) source = 'Parents'
      return { email: e, source }
    })

    setExisted(existedList)
    setNeedToAdd(needRows)
    setCompareSummary(
      `Compared CSV (${csvEmails.size}) vs DB (${dbSet.size} unique: ${u.size} users + ${p.size} parents).`,
    )
  }, [csvEmails, usersEmails, parentsEmails])

  const handleReset = useCallback(() => {
    setCsvEmails(new Set())
    setCsvSummary('')
    setCompareSummary('')
    setUsersText('')
    setParentsText('')
    setApiUrlInput(defaultApi)
    setExisted([])
    setNeedToAdd([])
  }, [defaultApi])

  return (
    <div className="container my-4">
      <h2 className="text-center mb-2">Parent Email Extractor</h2>
      <p className="text-center mb-4 text-muted">
        Upload a CSV file with emails, compare against your database emails, and see matches and gaps.
      </p>

      <div className="row g-3">
        <div className="col-12 col-lg-6">
          <div className="card shadow-sm">
            <div className="card-body">
              <h5 className="card-title mb-3">1) Upload CSV of emails (source)</h5>
              <div className="row g-2 align-items-center">
                <div className="col-12 col-md-8">
                  <input
                    type="file"
                    accept=".csv"
                    className="form-control"
                    onChange={(ev) => {
                      const f = ev.target.files?.[0]
                      void handleParseCsv(f)
                    }}
                  />
                </div>
              </div>
              <p className="text-muted small mt-2 mb-0">
                The CSV can be a single column of emails or multi-column. This tool extracts any values that look like
                emails.
              </p>
              {csvSummary ? <div className="text-muted small mt-2">{csvSummary}</div> : null}
            </div>
          </div>
        </div>

        <div className="col-12 col-lg-6">
          <div className="card shadow-sm h-100">
            <div className="card-body">
              <h5 className="card-title mb-3">2) Provide database emails</h5>
              <div className="mb-2">
                <span className="fw-semibold">Option A:</span> Paste emails (one per line)
              </div>
              <label className="form-label small text-muted">First parent&apos;s email</label>
              <textarea
                className="form-control"
                rows={4}
                placeholder={'user1@example.com\nuser2@example.com'}
                value={usersText}
                onChange={(e) => setUsersText(e.target.value)}
              />
              <label className="form-label small text-muted mt-3">Second parent&apos;s email</label>
              <textarea
                className="form-control"
                rows={4}
                placeholder={'parent1@example.com\nparent2@example.com'}
                value={parentsText}
                onChange={(e) => setParentsText(e.target.value)}
              />
              <div className="text-center text-muted my-2">— or —</div>
              <div className="mb-2">
                <span className="fw-semibold">Option B:</span> Fetch from API
              </div>
              <div className="row g-2 align-items-center">
                <div className="col-12 col-md-8">
                  <input
                    type="url"
                    className="form-control"
                    value={apiUrlInput}
                    onChange={(e) => setApiUrlInput(e.target.value)}
                  />
                </div>
                <div className="col-12 col-md-4 text-md-end">
                  <button type="button" className="btn btn-outline-secondary w-100" onClick={() => void handleFetchApi()}>
                    Fetch
                  </button>
                </div>
              </div>
              <p className="text-muted small mt-2 mb-0">
                Provide a backend endpoint that returns JSON like: <code>{'{"users": [...], "parents": [...]}'}</code>
              </p>
            </div>
          </div>
        </div>
      </div>

      <div className="card shadow-sm mt-3">
        <div className="card-body">
          <h5 className="card-title mb-3">3) Compare</h5>
          <div className="d-flex flex-wrap gap-2">
            <button type="button" className="btn btn-primary" onClick={handleCompare}>
              Run Comparison
            </button>
            <button type="button" className="btn btn-outline-secondary" onClick={handleReset}>
              Reset
            </button>
          </div>
          {compareSummary ? <div className="text-muted small mt-2">{compareSummary}</div> : null}

          <div className="row g-3 mt-2">
            <div className="col-12 col-lg-6">
              <div className="p-3 border rounded-3 bg-light">
                <h6 className="d-flex align-items-center gap-2 mb-2">
                  Existed emails <span className="badge bg-success-subtle text-success">{existed.length}</span>
                </h6>
                <div className="table-responsive" style={{ maxHeight: 320 }}>
                  <table className="table table-striped table-hover table-sm w-100">
                    <thead>
                      <tr>
                        <th>Email</th>
                      </tr>
                    </thead>
                    <tbody>
                      {existed.map((em) => (
                        <tr key={em}>
                          <td>{em}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <div className="d-flex justify-content-end mt-2">
                  <button
                    type="button"
                    className="btn btn-outline-secondary btn-sm"
                    onClick={() => downloadCSV('existed_emails.csv', existed)}
                  >
                    Download CSV
                  </button>
                </div>
              </div>
            </div>
            <div className="col-12 col-lg-6">
              <div className="p-3 border rounded-3 bg-light">
                <h6 className="d-flex align-items-center gap-2 mb-2">
                  Need to add email <span className="badge bg-danger-subtle text-danger">{needToAdd.length}</span>
                </h6>
                <div className="text-muted small mb-2">
                  Emails present in database (users or parents) but <strong>NOT</strong> in your uploaded CSV.
                </div>
                <div className="table-responsive" style={{ maxHeight: 320 }}>
                  <table className="table table-striped table-hover table-sm w-100">
                    <thead>
                      <tr>
                        <th>Email</th>
                        <th>Source</th>
                      </tr>
                    </thead>
                    <tbody>
                      {needToAdd.map((row) => (
                        <tr key={row.email}>
                          <td>{row.email}</td>
                          <td>{row.source}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <div className="d-flex justify-content-end mt-2">
                  <button
                    type="button"
                    className="btn btn-outline-secondary btn-sm"
                    onClick={() => downloadCSV('need_to_add_emails.csv', needToAdd.map((r) => r.email))}
                  >
                    Download CSV
                  </button>
                </div>
              </div>
            </div>
          </div>

          <div className="alert alert-info mt-3 mb-0 p-2">
            <ul className="mb-0 small">
              <li>Comparison is case-insensitive and trims whitespace.</li>
              <li>Duplicates are removed within each source before comparison.</li>
              <li>CSV parsing extracts any values that resemble valid email addresses from any column.</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  )
}
