import { useEffect, useMemo, useState } from 'react'
import { flushSync } from 'react-dom'
import {
  AlertTriangle,
  Loader2,
  Lock,
  Pencil,
  RefreshCw,
  Rocket,
  RotateCcw,
  Search,
  Trash2,
  Unlock,
} from 'lucide-react'
import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal'
import { Modal } from '../components/Modal'
import { ToggleSwitch } from '../components/ToggleSwitch'
import type { DomainListItem, DomainsListResponse } from '../types/domain'
import type { ListDomainsParams } from '../services/domainService'
import { ApiError, isAbortError } from '../lib/api'
import {
  deployDomain,
  listDomains,
  removeDomain,
  setDomainActive,
  setDomainSsl,
  syncSsl,
  updateDomain,
} from '../services/domainService'
import { useToast } from '../context/ToastContext'
import { Pagination } from '@meshkee/dashboard-ui'
import pageStyles from '../components/PageContent.module.css'
import tableStyles from './BusinessesPage.module.css'
import styles from './WebsitesPage.module.css'

const PAGE_SIZE = 10

function daysUntilExpiry(expiresAt: string | null) {
  if (!expiresAt) return null
  const diff = new Date(expiresAt).getTime() - Date.now()
  return Math.ceil(diff / (1000 * 60 * 60 * 24))
}

function formatDaysLeft(expiresAt: string | null) {
  const days = daysUntilExpiry(expiresAt)
  if (days === null) return '—'
  if (days < 0) return 'Expired'
  if (days === 0) return 'Today'
  if (days === 1) return '1 day'
  return `${days} days`
}

function daysLeftClass(expiresAt: string | null) {
  const days = daysUntilExpiry(expiresAt)
  if (days === null) return styles.daysOk
  if (days < 0) return styles.daysExpired
  if (days <= 30) return styles.daysWarn
  return styles.daysOk
}

function formatDeployAt(iso: string | null) {
  if (!iso) return '—'
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return '—'
  return d.toLocaleString(undefined, {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  })
}

function deployStatusLabel(status: DomainListItem['lastDeployStatus']) {
  if (status === 'started') return 'Started'
  if (status === 'failed') return 'Failed'
  return null
}

function deployStatusClass(status: DomainListItem['lastDeployStatus']) {
  if (status === 'started') return styles.deployOk
  if (status === 'failed') return styles.deployFail
  return undefined
}

export function WebsitesPage() {
  const { showToast } = useToast()
  const [data, setData] = useState<DomainsListResponse | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')

  const [appliedFilters, setAppliedFilters] = useState<Omit<ListDomainsParams, 'page' | 'pageSize'>>({})
  const [page, setPage] = useState(1)
  const [draftName, setDraftName] = useState('')

  const [editOpen, setEditOpen] = useState(false)
  const [editDomain, setEditDomain] = useState<DomainListItem | null>(null)
  const [editHost, setEditHost] = useState('')
  const [editExpiresAt, setEditExpiresAt] = useState('')
  const [editSubmitting, setEditSubmitting] = useState(false)
  const [editError, setEditError] = useState('')

  const [removeTarget, setRemoveTarget] = useState<DomainListItem | null>(null)
  const [togglingActiveId, setTogglingActiveId] = useState<number | null>(null)
  const [togglingSslId, setTogglingSslId] = useState<number | null>(null)
  const [deployingId, setDeployingId] = useState<DomainListItem['id'] | null>(null)
  const [syncingSsl, setSyncingSsl] = useState(false)

  useEffect(() => {
    const controller = new AbortController()

    async function load() {
      setLoading(true)
      setError('')
      try {
        const result = await listDomains(
          { page, pageSize: PAGE_SIZE, ...appliedFilters },
          controller.signal,
        )
        if (controller.signal.aborted) return
        setData(result)
      } catch (err) {
        if (isAbortError(err) || controller.signal.aborted) return
        setError(err instanceof ApiError ? err.message : 'Unable to load domains.')
      } finally {
        if (!controller.signal.aborted) setLoading(false)
      }
    }

    void load()

    return () => {
      controller.abort()
    }
  }, [page, appliedFilters.name])

  const totalPages = useMemo(() => {
    const total = data?.total ?? 0
    return Math.max(1, Math.ceil(total / PAGE_SIZE))
  }, [data?.total])

  const showingFrom = useMemo(() => {
    if (!data) return 0
    return (page - 1) * PAGE_SIZE + 1
  }, [data, page])

  const showingTo = useMemo(() => {
    if (!data) return 0
    return Math.min(data.total, page * PAGE_SIZE)
  }, [data, page])

  function applyFilters() {
    setPage(1)
    setAppliedFilters(draftName.trim() ? { name: draftName.trim() } : {})
  }

  function clearFilters() {
    setDraftName('')
    setPage(1)
    setAppliedFilters({})
  }

  function openEdit(domain: DomainListItem) {
    setEditDomain(domain)
    setEditHost(domain.host)
    setEditExpiresAt(domain.expiresAt ? domain.expiresAt.slice(0, 10) : '')
    setEditError('')
    setEditOpen(true)
  }

  async function submitEdit() {
    if (!editDomain) return
    setEditSubmitting(true)
    setEditError('')
    try {
      await updateDomain(editDomain.id, {
        host: editHost.trim(),
        ...(editExpiresAt ? { expiresAt: new Date(editExpiresAt).toISOString() } : {}),
      })
      setEditOpen(false)
      setEditDomain(null)
      showToast(`"${editHost.trim()}" has been updated.`, 'success')
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          items: prev.items.map((item) =>
            item.id === editDomain.id
              ? {
                  ...item,
                  host: editHost.trim(),
                  expiresAt: editExpiresAt ? new Date(editExpiresAt).toISOString() : item.expiresAt,
                }
              : item,
          ),
        }
      })
    } catch (err) {
      setEditError(err instanceof ApiError ? err.message : 'Unable to update domain.')
    } finally {
      setEditSubmitting(false)
    }
  }

  async function handleToggleActive(domain: DomainListItem, isActive: boolean) {
    setTogglingActiveId(domain.id)
    setError('')
    setData((prev) => {
      if (!prev) return prev
      return {
        ...prev,
        items: prev.items.map((item) => (item.id === domain.id ? { ...item, isActive } : item)),
      }
    })
    try {
      await setDomainActive(domain.id, isActive)
      showToast(`"${domain.host}" has been ${isActive ? 'enabled' : 'disabled'}.`, 'success')
    } catch (err) {
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          items: prev.items.map((item) =>
            item.id === domain.id ? { ...item, isActive: !isActive } : item,
          ),
        }
      })
      setError(err instanceof ApiError ? err.message : 'Unable to update domain status.')
    } finally {
      setTogglingActiveId(null)
    }
  }

  async function handleToggleSsl(domain: DomainListItem, sslEnabled: boolean) {
    setTogglingSslId(domain.id)
    setError('')
    setData((prev) => {
      if (!prev) return prev
      return {
        ...prev,
        items: prev.items.map((item) => (item.id === domain.id ? { ...item, sslEnabled } : item)),
      }
    })
    try {
      await setDomainSsl(domain.id, sslEnabled)
      showToast(
        `SSL ${sslEnabled ? 'enabled' : 'disabled'} for "${domain.host}".`,
        'success',
      )
    } catch (err) {
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          items: prev.items.map((item) =>
            item.id === domain.id ? { ...item, sslEnabled: !sslEnabled } : item,
          ),
        }
      })
      setError(err instanceof ApiError ? err.message : 'Unable to update SSL status.')
    } finally {
      setTogglingSslId(null)
    }
  }

  async function handleSyncSsl() {
    if (syncingSsl) return

    flushSync(() => {
      setSyncingSsl(true)
    })
    setError('')
    showToast('Starting SSL sync…', 'info')

    try {
      const result = await syncSsl()
      showToast(result.message || 'SSL sync started.', 'success')
    } catch (err) {
      const message = err instanceof ApiError ? err.message : 'Unable to start SSL sync.'
      setError(message)
      showToast(message, 'error')
    } finally {
      setSyncingSsl(false)
    }
  }

  async function handleDeploy(domain: DomainListItem) {
    if (!domain.deploySlug) return
    if (deployingId != null) return

    // Paint spinner + disabled state before the network call starts
    flushSync(() => {
      setDeployingId(domain.id)
    })
    setError('')
    showToast(`Deploying "${domain.host}"…`, 'info')

    try {
      const result = await deployDomain(domain.id)
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          items: prev.items.map((item) =>
            item.id === domain.id
              ? {
                  ...item,
                  lastDeployedAt: result.lastDeployedAt,
                  lastDeployStatus: result.lastDeployStatus,
                }
              : item,
          ),
        }
      })
      showToast(`Deploy started for "${result.host}".`, 'success')
    } catch (err) {
      const message = err instanceof ApiError ? err.message : 'Deploy failed to start.'
      setError(message)
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          items: prev.items.map((item) =>
            item.id === domain.id
              ? {
                  ...item,
                  lastDeployedAt: new Date().toISOString(),
                  lastDeployStatus: 'failed',
                }
              : item,
          ),
        }
      })
      showToast(message, 'error')
    } finally {
      setDeployingId(null)
    }
  }

  async function confirmRemove() {
    if (!removeTarget) return
    setError('')
    try {
      await removeDomain(removeTarget.id)
      setRemoveTarget(null)
      showToast(`"${removeTarget.host}" has been removed.`, 'success')
      setData((prev) => {
        if (!prev) return prev
        return {
          ...prev,
          total: Math.max(0, prev.total - 1),
          items: prev.items.filter((item) => item.id !== removeTarget.id),
        }
      })
    } catch (err) {
      setError(err instanceof ApiError ? err.message : 'Unable to remove domain.')
    }
  }

  return (
    <main className={pageStyles.content}>
      <div className={pageStyles.pageHeader}>
        <div>
          <h2 className={pageStyles.pageTitle}>Websites</h2>
          <p className={pageStyles.pageSubtitle}>
            Monitor and manage all domains across the platform.
          </p>
        </div>
        <button
          type="button"
          className={`${tableStyles.btn} ${tableStyles.btnPrimary} ${
            syncingSsl ? styles.deployBusy : ''
          }`}
          onClick={() => void handleSyncSsl()}
          disabled={syncingSsl}
          aria-busy={syncingSsl}
        >
          {syncingSsl ? (
            <Loader2 size={16} className={styles.spin} aria-hidden />
          ) : (
            <RefreshCw size={16} aria-hidden />
          )}
          {syncingSsl ? 'Syncing SSL…' : 'Sync SSL now'}
        </button>
      </div>

      <div className={tableStyles.filtersPanel}>
        <div className={tableStyles.filtersTitle}>Filters</div>
        <div className={tableStyles.filtersGrid}>
          <div className={tableStyles.filtersInputs}>
            <div className={`${tableStyles.field} ${tableStyles.fieldCol3}`}>
              <label htmlFor="filter-domain-name">Name</label>
              <input
                id="filter-domain-name"
                value={draftName}
                onChange={(e) => setDraftName(e.target.value)}
                placeholder="shop-a.local"
              />
            </div>
          </div>
          <div className={tableStyles.filterActions}>
            <button
              type="button"
              className={`${tableStyles.iconActionBtn} ${tableStyles.iconActionBtnPrimary}`}
              onClick={applyFilters}
              disabled={loading}
              aria-label="Search"
              title="Search"
            >
              <Search size={18} />
            </button>
            <button
              type="button"
              className={`${tableStyles.iconActionBtn} ${tableStyles.iconActionBtnGhost}`}
              onClick={clearFilters}
              disabled={loading}
              aria-label="Clear filters"
              title="Clear filters"
            >
              <RotateCcw size={18} />
            </button>
          </div>
        </div>
      </div>

      <div className={tableStyles.tablePanel}>
        <div className={tableStyles.tableWrap}>
          <div className={tableStyles.tableHeader}>
            <div className={tableStyles.tableHeaderTitle}>Domain list</div>
            <div className={tableStyles.meta}>
              {data ? (
                <>
                  Showing {showingFrom} - {showingTo} of {data.total}
                </>
              ) : (
                ' '
              )}
            </div>
          </div>

          {error && (
            <div style={{ padding: 16 }}>
              <div className={tableStyles.meta} style={{ color: '#b91c1c' }}>
                {error}
              </div>
            </div>
          )}

          <div style={{ overflowX: 'auto' }}>
            <table className={tableStyles.table}>
              <thead>
                <tr>
                  <th className={tableStyles.th}>Name</th>
                  <th className={tableStyles.th}>Owner business</th>
                  <th className={tableStyles.th}>Days to expire</th>
                  <th className={tableStyles.th}>SSL</th>
                  <th className={tableStyles.th}>Latest deploy</th>
                  <th className={`${tableStyles.th} ${tableStyles.thActions}`}>Actions</th>
                </tr>
              </thead>
              <tbody>
                {loading && (
                  <tr>
                    <td className={tableStyles.td} colSpan={6}>
                      Loading...
                    </td>
                  </tr>
                )}

                {!loading && data?.items?.length === 0 && (
                  <tr>
                    <td className={tableStyles.td} colSpan={6}>
                      No results found.
                    </td>
                  </tr>
                )}

                {!loading &&
                  data?.items?.map((domain) => (
                    <tr
                      key={domain.id}
                      className={!domain.isActive ? styles.inactiveRow : undefined}
                    >
                      <td className={tableStyles.td}>{domain.host}</td>
                      <td className={tableStyles.td}>{domain.businessName}</td>
                      <td className={tableStyles.td}>
                        <span className={daysLeftClass(domain.expiresAt)}>
                          {formatDaysLeft(domain.expiresAt)}
                        </span>
                      </td>
                      <td className={tableStyles.td}>
                        <div className={tableStyles.domainCell}>
                          {domain.sslEnabled ? (
                            <span
                              className={tableStyles.sslIcon}
                              title="SSL certificate valid"
                              aria-label="SSL certificate valid"
                            >
                              <Lock size={16} className={tableStyles.sslOk} aria-hidden="true" />
                            </span>
                          ) : (
                            <span
                              className={tableStyles.sslIcon}
                              title="SSL certificate missing or invalid"
                              aria-label="SSL certificate missing or invalid"
                            >
                              <AlertTriangle
                                size={16}
                                className={tableStyles.sslWarn}
                                aria-hidden="true"
                              />
                            </span>
                          )}
                          <span className={tableStyles.subText}>
                            {domain.sslEnabled ? 'Valid' : 'Invalid'}
                          </span>
                        </div>
                      </td>
                      <td className={tableStyles.td}>
                        {domain.lastDeployedAt ? (
                          <div className={styles.deployCell}>
                            <span className={tableStyles.subText}>
                              {formatDeployAt(domain.lastDeployedAt)}
                            </span>
                            {deployStatusLabel(domain.lastDeployStatus) ? (
                              <span
                                className={`${styles.deployStatus} ${deployStatusClass(domain.lastDeployStatus) ?? ''}`}
                              >
                                {deployStatusLabel(domain.lastDeployStatus)}
                              </span>
                            ) : null}
                          </div>
                        ) : (
                          <span className={tableStyles.subText}>—</span>
                        )}
                      </td>
                      <td className={`${tableStyles.td} ${tableStyles.tdActions}`}>
                        <div className={tableStyles.rowActions}>
                          <span className={tableStyles.toggleInActions}>
                            <ToggleSwitch
                              checked={domain.isActive}
                              disabled={togglingActiveId === domain.id}
                              ariaLabel={`${domain.isActive ? 'Disable' : 'Enable'} ${domain.host}`}
                              onChange={(isActive) => void handleToggleActive(domain, isActive)}
                            />
                          </span>
                          {domain.deploySlug ? (
                            <button
                              type="button"
                              className={`${tableStyles.controlBtn} ${
                                deployingId === domain.id ? styles.deployBusy : ''
                              }`}
                              onClick={() => {
                                if (deployingId != null) return
                                void handleDeploy(domain)
                              }}
                              disabled={deployingId === domain.id}
                              title={
                                deployingId === domain.id ? 'Deploying…' : 'Deploy website'
                              }
                              aria-label={
                                deployingId === domain.id ? 'Deploying' : 'Deploy website'
                              }
                              aria-busy={deployingId === domain.id}
                            >
                              {deployingId === domain.id ? (
                                <Loader2 size={16} className={styles.spin} aria-hidden />
                              ) : (
                                <Rocket size={16} />
                              )}
                            </button>
                          ) : null}
                          <button
                            type="button"
                            className={tableStyles.controlBtn}
                            onClick={() => void handleToggleSsl(domain, !domain.sslEnabled)}
                            disabled={togglingSslId === domain.id}
                            title={domain.sslEnabled ? 'Disable SSL' : 'Enable SSL'}
                            aria-label={domain.sslEnabled ? 'Disable SSL' : 'Enable SSL'}
                          >
                            {domain.sslEnabled ? <Lock size={16} /> : <Unlock size={16} />}
                          </button>
                          <button
                            type="button"
                            className={tableStyles.controlBtn}
                            onClick={() => openEdit(domain)}
                            title="Edit"
                            aria-label="Edit"
                          >
                            <Pencil size={16} />
                          </button>
                          <button
                            type="button"
                            className={`${tableStyles.controlBtn} ${tableStyles.controlBtnDanger}`}
                            onClick={() => setRemoveTarget(domain)}
                            title="Remove"
                            aria-label="Remove"
                          >
                            <Trash2 size={16} />
                          </button>
                        </div>
                      </td>
                    </tr>
                  ))}
              </tbody>
            </table>
          </div>

          <div className={tableStyles.pagination}>
            <div>
              Page {page} / {totalPages} · {PAGE_SIZE} per page · {data?.total ?? 0} total
            </div>
            <Pagination
              currentPage={page}
              totalPages={totalPages}
              onPageChange={setPage}
              disabled={loading}
              variant="inline"
            />
          </div>
        </div>
      </div>

      <Modal
        open={editOpen}
        title="Edit domain"
        onClose={() => {
          setEditOpen(false)
          setEditDomain(null)
          setEditError('')
        }}
      >
        {editError ? (
          <p className={tableStyles.alertError} role="alert">
            {editError}
          </p>
        ) : null}
        <div className={tableStyles.field}>
          <label htmlFor="edit-domain-host">Domain name</label>
          <input
            id="edit-domain-host"
            value={editHost}
            onChange={(e) => setEditHost(e.target.value)}
            disabled={editSubmitting}
          />
        </div>
        <div style={{ height: 10 }} />
        <div className={tableStyles.field}>
          <label htmlFor="edit-domain-expires">Expiry date</label>
          <input
            id="edit-domain-expires"
            type="date"
            value={editExpiresAt}
            onChange={(e) => setEditExpiresAt(e.target.value)}
            disabled={editSubmitting}
          />
        </div>
        <div style={{ height: 12 }} />
        <div className={tableStyles.actionsRow}>
          <button
            type="button"
            className={`${tableStyles.btn} ${tableStyles.btnGhost}`}
            onClick={() => setEditOpen(false)}
            disabled={editSubmitting}
          >
            Cancel
          </button>
          <button
            type="button"
            className={`${tableStyles.btn} ${tableStyles.btnPrimary}`}
            onClick={() => void submitEdit()}
            disabled={editSubmitting || !editHost.trim()}
          >
            Save
          </button>
        </div>
      </Modal>

      <ConfirmDeleteModal
        open={removeTarget !== null}
        title="Remove domain?"
        message={
          removeTarget
            ? `Are you sure you want to remove "${removeTarget.host}"? This action cannot be undone.`
            : ''
        }
        onCancel={() => setRemoveTarget(null)}
        onConfirm={() => void confirmRemove()}
      />
    </main>
  )
}
