import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import {
  Badge, Button, ConfirmDialog, DataTable, Dialog, EmptyState, ErrorState, FilterChips,
  FormField, FormGrid, Notice, PageHeader, Skeleton, Toolbar, useToast,
} from '@sims/ui'
import {
  createTicket, getBranches, getClients, getEmployees, getTickets, patchTicket, staffId,
  TICKET_STATUSES,
  type Branch, type Client, type Employee, type Ticket, type TicketStatus,
} from '../api'
import { useData } from './Clients'

const PAGE_SIZE = 50

/** The five APEX service lines (D20 design §1) — suggestions only; module stays free text. */
export const TICKET_MODULE_CODES = ['SMS', 'RTGS', 'WHATSAPP', 'MOBILEAPP', 'ATM']

export const TICKET_STATUS_LABEL: Record<TicketStatus, string> = {
  open: 'Open', in_progress: 'In progress', waiting: 'Waiting', closed: 'Closed', dropped: 'Dropped',
}

export const TICKET_TONE: Record<TicketStatus, 'ok' | 'warn' | 'err' | 'accent' | undefined> = {
  open: 'accent', in_progress: 'warn', waiting: undefined, closed: 'ok', dropped: 'err',
}

/** Description cell: truncated with the full text on hover (title). */
export function TicketDescription(props: { text: string }) {
  if (props.text === '') return <>—</>
  return (
    <span
      title={props.text}
      style={{
        display: 'inline-block', maxWidth: 340, overflow: 'hidden',
        textOverflow: 'ellipsis', whiteSpace: 'nowrap', verticalAlign: 'bottom',
      }}
    >
      {props.text}
    </span>
  )
}

/**
 * The workbench transitions: open→Start/Waiting, in progress→Waiting/Close,
 * waiting→Start/Close, terminal→Reopen; Drop asks first (it stays on record).
 */
export function TicketActions(props: { t: Ticket; onDone: () => void; onError: (m: string) => void }) {
  const [busy, setBusy] = useState(false)
  const [dropping, setDropping] = useState(false)
  const go = (status: TicketStatus) => {
    if (busy) return
    setBusy(true)
    patchTicket(props.t.id, { status })
      .then(props.onDone)
      .catch((e: Error) => props.onError(e.message))
      .finally(() => setBusy(false))
  }
  const s = props.t.status
  return (
    <span style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
      {(s === 'open' || s === 'waiting') && <Button tone="primary" disabled={busy} onClick={() => go('in_progress')}>Start</Button>}
      {(s === 'open' || s === 'in_progress') && <Button disabled={busy} onClick={() => go('waiting')}>Waiting</Button>}
      {(s === 'in_progress' || s === 'waiting') && <Button tone="primary" disabled={busy} onClick={() => go('closed')}>Close</Button>}
      {(s === 'closed' || s === 'dropped') && <Button disabled={busy} onClick={() => go('open')}>Reopen</Button>}
      {s !== 'closed' && s !== 'dropped' && (
        <Button tone="danger" disabled={busy} onClick={() => setDropping(true)}>Drop</Button>
      )}
      {dropping && (
        <ConfirmDialog
          open
          onClose={() => setDropping(false)}
          onConfirm={() => { setDropping(false); go('dropped') }}
          title="Drop ticket"
          body={`Drop this ${props.t.kind !== '' ? `${props.t.kind} ` : ''}ticket for ${props.t.clientName}? It stays on record as dropped and can be reopened.`}
          confirmLabel="Drop"
          tone="danger"
        />
      )}
    </span>
  )
}

/** Per-row assignment — '' = unassigned (PATCH sends null to clear). */
export function TicketAssignSelect(props: {
  t: Ticket; employees: Employee[]; onDone: () => void; onError: (m: string) => void
}) {
  return (
    <select
      className="wf" aria-label="Assigned to" value={props.t.assignedTo ?? ''}
      onChange={(e) => {
        patchTicket(props.t.id, { assignedTo: e.target.value !== '' ? e.target.value : null })
          .then(props.onDone).catch((err: Error) => props.onError(err.message))
      }}
    >
      <option value="">— unassigned —</option>
      {props.employees
        .filter((emp) => emp.active || emp.id === props.t.assignedTo)
        .map((emp) => <option key={emp.id} value={emp.id}>{emp.displayName}</option>)}
    </select>
  )
}

/**
 * New-ticket dialog. Client via type-ahead (Modules assign pattern) unless the
 * caller pre-picks one (Client 360 tab); branches load once a client is picked;
 * module and kind are free text with suggestions (config over code — kinds come
 * from history via the list response).
 */
export function NewTicketDialog(props: {
  open: boolean; onClose: () => void; onCreated: () => void
  kinds: string[]
  /** Pre-picked client (Client 360) — hides the type-ahead. */
  initialClient?: { id: string; code: string; name: string }
}) {
  const toast = useToast()
  const [q, setQ] = useState('')
  const [hits, setHits] = useState<Client[]>([])
  const [pick, setPick] = useState<{ id: string; code: string; name: string } | undefined>()
  const [branches, setBranches] = useState<Branch[]>([])
  const [f, setF] = useState({ branchId: '', moduleCode: '', kind: '', description: '', onlineOffline: '' })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    setError(undefined)
    setQ(''); setHits([]); setPick(props.initialClient)
    setF({ branchId: '', moduleCode: '', kind: '', description: '', onlineOffline: '' })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [props.open, props.initialClient?.id])

  useEffect(() => {
    if (pick === undefined) { setBranches([]); return }
    getBranches(pick.id).then(setBranches).catch(() => setBranches([]))
  }, [pick])

  const set = (k: keyof typeof f) => (e: { target: { value: string } }) =>
    setF((p) => ({ ...p, [k]: e.target.value }))
  const search = (text: string) => {
    setQ(text); setPick(undefined); setF((p) => ({ ...p, branchId: '' }))
    if (text.trim().length < 2) { setHits([]); return }
    getClients(text).then((cs) => setHits(cs.slice(0, 6))).catch(() => setHits([]))
  }

  const save = () => {
    if (saving) return
    if (pick === undefined) { setError('Pick a client'); return }
    setError(undefined)
    setSaving(true)
    createTicket({
      clientId: pick.id,
      ...(f.branchId !== '' ? { branchId: f.branchId } : {}),
      ...(f.moduleCode.trim() !== '' ? { moduleCode: f.moduleCode.trim() } : {}),
      ...(f.kind.trim() !== '' ? { kind: f.kind.trim() } : {}),
      ...(f.description.trim() !== '' ? { description: f.description.trim() } : {}),
      ...(f.onlineOffline !== '' ? { onlineOffline: f.onlineOffline } : {}),
    })
      .then(() => { toast.ok('Ticket created'); props.onCreated(); props.onClose() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title="New ticket"
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" disabled={saving} onClick={save}>{saving ? 'Saving…' : 'Create ticket'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Client" wide>
          {props.initialClient !== undefined
            ? <input className="wf" value={`${props.initialClient.code} · ${props.initialClient.name}`} disabled />
            : (
              <>
                <input
                  className="wf" autoFocus placeholder="Search name / code…"
                  value={pick !== undefined ? `${pick.code} · ${pick.name}` : q}
                  onChange={(e) => search(e.target.value)}
                />
                {pick === undefined && hits.length > 0 && (
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 6 }}>
                    {hits.map((c) => (
                      <Button key={c.id} onClick={() => setPick({ id: c.id, code: c.code, name: c.name })}>{c.code} · {c.name}</Button>
                    ))}
                  </div>
                )}
              </>
            )}
        </FormField>
        <FormField label="Branch">
          <select
            className="wf" value={f.branchId} onChange={set('branchId')}
            disabled={pick === undefined || branches.length === 0}
          >
            <option value="">
              {pick === undefined ? 'Pick a client first' : branches.length === 0 ? 'No branches' : '— head office —'}
            </option>
            {branches.filter((b) => b.active).map((b) => (
              <option key={b.id} value={b.id}>{b.name}{b.code !== null ? ` (${b.code})` : ''}</option>
            ))}
          </select>
        </FormField>
        <FormField label="Module">
          <input
            className="wf" list="hq-ticket-modules" placeholder="SMS / RTGS / …"
            value={f.moduleCode} onChange={set('moduleCode')}
          />
        </FormField>
        <FormField label="Kind">
          <input
            className="wf" list="hq-ticket-kinds" placeholder="e.g. NEW WORK"
            value={f.kind} onChange={set('kind')}
          />
        </FormField>
        <FormField label="Online / offline">
          <select className="wf" value={f.onlineOffline} onChange={set('onlineOffline')}>
            <option value="">—</option>
            <option value="online">online</option>
            <option value="offline">offline</option>
          </select>
        </FormField>
        <FormField label="Description" wide>
          <textarea className="wf" rows={3} value={f.description} onChange={set('description')} />
        </FormField>
      </FormGrid>
      <datalist id="hq-ticket-modules">
        {TICKET_MODULE_CODES.map((m) => <option key={m} value={m} />)}
      </datalist>
      <datalist id="hq-ticket-kinds">
        {props.kinds.map((k) => <option key={k} value={k} />)}
      </datalist>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}

/**
 * Ticket desk (D20 — APEX work-bench parity): team-visible, "Mine" is a filter
 * not a gate (support staff pick up unassigned work). Chips carry whole-desk
 * per-status counts; search hits description/kind/client; honest pagination.
 */
export function Tickets() {
  const [status, setStatus] = useState('open')
  const [scope, setScope] = useState<'all' | 'mine'>('all')
  const [q, setQ] = useState('')
  const [page, setPage] = useState(1)
  const [err, setErr] = useState('')
  const [creating, setCreating] = useState(false)
  const me = staffId()
  const employees = useData(() => getEmployees(), [])

  const list = useData(
    () => getTickets({
      ...(status !== 'all' ? { status: status as TicketStatus } : {}),
      ...(scope === 'mine' ? { mine: true } : {}),
      ...(q !== '' ? { q } : {}),
      page, pageSize: PAGE_SIZE,
    }),
    [status, scope, q, page],
  )

  const data = list.data
  const rows = data?.tickets
  const counts = data?.counts
  const allCount = counts !== undefined ? Object.values(counts).reduce((a, b) => a + b, 0) : 0
  const totalPages = data !== undefined ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1
  const from = data !== undefined && data.total > 0 ? (data.page - 1) * data.pageSize + 1 : 0
  const to = data !== undefined ? Math.min(data.page * data.pageSize, data.total) : 0

  return (
    <div className="wf-page">
      <PageHeader
        title="Tickets"
        desc="The support work bench — every service call across all clients. Anyone can pick up unassigned work."
        actions={<Button tone="primary" onClick={() => setCreating(true)}>New ticket</Button>}
      />
      <Toolbar>
        <FilterChips
          chips={[
            { key: 'all', label: 'All', count: allCount },
            ...TICKET_STATUSES.map((s) => ({
              key: s, label: TICKET_STATUS_LABEL[s], count: counts?.[s] ?? 0,
            })),
          ]}
          active={status}
          onChange={(k) => { setStatus(k); setPage(1) }}
        />
        {me !== '' && (
          <FilterChips
            chips={[{ key: 'all', label: 'All' }, { key: 'mine', label: 'Mine' }]}
            active={scope}
            onChange={(k) => { setScope(k as 'all' | 'mine'); setPage(1) }}
          />
        )}
        <input
          className="wf" style={{ maxWidth: 240 }} placeholder="Search description / kind / client…"
          value={q} onChange={(e) => { setQ(e.target.value); setPage(1) }}
        />
        <span style={{ flex: 1 }} />
        {data !== undefined && <Badge>{data.total} total</Badge>}
      </Toolbar>
      {err !== '' && <Notice tone="err">{err}</Notice>}
      {list.error !== undefined && <ErrorState message={list.error} onRetry={list.reload} />}
      {list.error !== undefined ? null
        : rows === undefined ? <Skeleton rows={6} />
        : rows.length === 0 ? (
          <EmptyState>
            No {status !== 'all' ? TICKET_STATUS_LABEL[status as TicketStatus].toLowerCase() : ''} tickets
            {scope === 'mine' ? ' of yours' : ''}{q !== '' ? ` matching “${q}”` : ''}.
          </EmptyState>
        ) : (
        <>
          <DataTable
            columns={[
              { key: 'opened', label: 'Opened' },
              { key: 'client', label: 'Client' },
              { key: 'branch', label: 'Branch' },
              { key: 'module', label: 'Module', mono: true },
              { key: 'kind', label: 'Kind' },
              { key: 'desc', label: 'Description' },
              { key: 'assigned', label: 'Assigned' },
              { key: 'status', label: 'Status' },
              { key: 'act', label: '' },
            ]}
            rows={rows.map((t) => ({
              opened: t.openedOn,
              client: <Link to={`/clients/${t.clientId}`}>{t.clientName}</Link>,
              branch: t.branchName ?? '—',
              module: t.moduleCode ?? '—',
              kind: t.kind !== '' ? t.kind : '—',
              desc: <TicketDescription text={t.description} />,
              assigned: employees.data !== undefined
                ? <TicketAssignSelect t={t} employees={employees.data.employees} onDone={list.reload} onError={setErr} />
                : (t.assignedName ?? '—'),
              status: <Badge tone={TICKET_TONE[t.status]}>{TICKET_STATUS_LABEL[t.status]}</Badge>,
              act: <TicketActions t={t} onDone={list.reload} onError={setErr} />,
            }))}
          />
          <Toolbar>
            <Badge>Showing {from}–{to} of {data!.total}</Badge>
            <span style={{ flex: 1 }} />
            <button
              type="button" className="wf" disabled={data!.page <= 1}
              onClick={() => setPage((p) => Math.max(1, p - 1))}
            >
              ‹ Prev
            </button>
            <span style={{ fontSize: 12, opacity: 0.7 }}>Page {data!.page} / {totalPages}</span>
            <button
              type="button" className="wf" disabled={data!.page >= totalPages}
              onClick={() => setPage((p) => p + 1)}
            >
              Next ›
            </button>
          </Toolbar>
        </>
      )}
      <NewTicketDialog
        open={creating}
        onClose={() => setCreating(false)}
        onCreated={() => list.reload()}
        kinds={data?.kinds ?? []}
      />
    </div>
  )
}
