import { useState, type ReactNode } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { formatINR } from '@sims/domain'
import { Badge, DataTable, EmptyState, ErrorState, Notice, Skeleton, StatCard, Stats } from '@sims/ui'
import { displayName, getDashboard, getSmsBalances, getStalledProjects, isManagerial } from '../api'
import { QueueActions, RULE_LABEL, reminderTone } from '../components/ReminderQueue'
import { useData } from './Clients'

const inr = (p: number) => formatINR(p)

/** 'YYYY-MM-DD' → 'Sunday 19 July 2026' (falls back to the raw string if unparseable). */
const longDate = (iso: string): string => {
  const d = new Date(`${iso}T00:00:00`)
  return Number.isNaN(d.getTime())
    ? iso
    : d.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })
}
/** 'YYYY-MM-DD' → '19 Jul' (falls back to the raw string if unparseable). */
const shortDate = (iso: string): string => {
  const d = new Date(`${iso}T00:00:00`)
  return Number.isNaN(d.getTime()) ? iso : d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })
}

/**
 * Dashboard home — the "cockpit" (D29): a Today hero strip, the four KPI stat
 * cards, the reminder queue, then a bento grid of the day's sections. Low-colour
 * on purpose — ink + neutrals + one teal accent, red only for real failures.
 */
export function Dashboard() {
  const nav = useNavigate()
  // My Day (D18 WS-E): owner/manager toggle Mine ↔ Everyone; staff are always
  // scoped to their own book server-side, so they get no toggle.
  const managerial = isManagerial()
  const [mine, setMine] = useState(false)
  const dash = useData(() => getDashboard(mine), [mine])
  const smsLow = useData(getSmsBalances, []) // D28: low-balance alert, seen even without opening the SMS screen
  const stalled = useData(getStalledProjects, []) // parked onboarding — active projects with no recent progress
  const [err, setErr] = useState('')
  const v = dash.data
  const name = displayName()

  return (
    <div className="wf-page">
      {dash.error !== undefined && <ErrorState message={dash.error} onRetry={dash.reload} />}
      {err !== '' && <Notice tone="err">{err}</Notice>}
      {v === undefined && dash.error === undefined ? <Skeleton rows={6} /> : v === undefined ? null : (
        <>
          {/* Today hero — date, greeting, the headline overdue figure, scope + quick actions. */}
          <section className="dash-hero">
            <div className="dash-hero-l">
              <div className="dash-hero-eyebrow">{longDate(v.today)}</div>
              <h1>Welcome back{name !== '' ? `, ${name}` : ''}</h1>
              <p>Here’s what needs you today — dues to chase, renewals landing, and the reminder queue.</p>
              {managerial && (
                <div className="dash-seg" role="group" aria-label="Scope">
                  <button type="button" className={!mine ? 'on' : ''} onClick={() => setMine(false)}>Everyone</button>
                  <button type="button" className={mine ? 'on' : ''} onClick={() => setMine(true)}>Mine</button>
                </div>
              )}
            </div>
            <div className="dash-hero-r">
              <div className="dash-money">
                <div className="k">Overdue</div>
                <div className="v num">{inr(v.totals.overduePaise)}</div>
              </div>
              <div className="dash-hero-actions">
                <button type="button" className="wf primary" onClick={() => nav('/documents/new')}>New document</button>
                <button type="button" className="wf" onClick={() => nav('/clients?new=1')}>New client</button>
              </div>
            </div>
          </section>

          {/* SMS low-balance alert (D28) — surfaced here so it's seen without opening the SMS screen. */}
          {smsLow.data !== undefined && smsLow.data.lowCount > 0 && (
            <Notice tone="warn">
              <Link to="/sms-balances" style={{ color: 'inherit', fontWeight: 600 }}>
                {smsLow.data.lowCount} SMS client{smsLow.data.lowCount === 1 ? '' : 's'} low on balance — review &amp; top up →
              </Link>
            </Notice>
          )}

          {/* KPIs — the app's existing stat cards (kept minimal; red only when a send failed). */}
          <Stats>
            <StatCard label="Overdue" value={inr(v.totals.overduePaise)} hint={`${v.overdue.length} invoice(s)`} />
            <StatCard label="Queued reminders" value={String(v.totals.queued)} />
            <StatCard label="Failed sends" value={String(v.totals.failed)} {...(v.totals.failed > 0 ? { hint: 'needs attention', hintTone: 'err' as const } : {})} />
            <StatCard label="Follow-ups today" value={String(v.followUpsToday.length)} />
          </Stats>

          {/* Reminder queue — full send/preview/dismiss actions preserved. */}
          <section className="dash-queue">
            <div className="dash-head">
              <h3>Reminder queue</h3>
              <span className="count">{v.queueTotal}</span>
              <Link to="/reminders">View all →</Link>
            </div>
            {v.queue.length === 0 ? <EmptyState>Nothing waiting — all clear.</EmptyState> : (
              <DataTable
                columns={[
                  { key: 'kind', label: 'Kind' }, { key: 'client', label: 'Client' },
                  { key: 'ref', label: 'Reference' }, { key: 'status', label: 'Status' },
                  { key: 'error', label: 'Error' }, { key: 'act', label: '' },
                ]}
                rowTone={(i) => (v.queue[i]?.status === 'failed' ? 'err' : undefined)}
                rows={v.queue.map((rem) => ({
                  kind: rem.label !== '' ? rem.label : RULE_LABEL[rem.ruleKind] ?? rem.ruleKind,
                  client: rem.clientName,
                  ref: rem.docNo ?? rem.duePeriod,
                  status: <Badge tone={reminderTone(rem.status)}>{rem.status}</Badge>,
                  error: rem.error ?? '—',
                  act: <QueueActions rem={rem} onDone={dash.reload} onError={setErr} />,
                }))}
              />
            )}
            {v.queueTotal > v.queue.length && (
              // No silent caps (rule 8): the table is the first page only — say so.
              <p className="dash-cap">
                Showing {v.queue.length} of {v.queueTotal} — <Link to="/reminders">see the full queue</Link>.
              </p>
            )}
          </section>

          {/* Bento — the day's read-only sections. */}
          <div className="dash-bento">
            <Card title="Overdue invoices" count={v.overdue.length} empty="No overdue invoices." isEmpty={v.overdue.length === 0}>
              {v.overdue.map((o) => (
                <Row key={o.docId} onClick={() => nav(`/documents/${o.docId}`)}
                  title={<span className="mono">{o.docNo ?? '—'}</span>} sub={o.clientName}
                  right={inr(o.outstandingPaise)} rightSub={`${o.daysOverdue}d overdue`} />
              ))}
            </Card>

            <Card title="Due this week" count={v.dueThisWeek.length} empty="No recurring bills due this week." isEmpty={v.dueThisWeek.length === 0}>
              {v.dueThisWeek.map((d) => (
                <Row key={d.planId} onClick={() => nav(`/clients/${d.clientId}`)}
                  title={d.clientName} sub={`runs ${shortDate(d.nextRun)}`}
                  {...(d.amountPaise !== null ? { right: inr(d.amountPaise) } : { rightSub: 'from price book' })} />
              ))}
            </Card>

            <Card title="Renewals this month" count={v.renewalsThisMonth.length} link={{ to: '/renewals' }} empty="No renewals this month." isEmpty={v.renewalsThisMonth.length === 0}>
              {v.renewalsThisMonth.map((r) => (
                <Row key={r.clientModuleId} onClick={() => nav(`/clients/${r.clientId}`)}
                  title={r.clientName} rightSub={shortDate(r.nextRenewal)} />
              ))}
            </Card>

            <Card
              title="Onboarding stalled" count={stalled.data?.length ?? 0}
              empty="Nothing stalled."
              // A fetch failure is not the same as a genuine empty result — show the error
              // (with retry) instead of quietly reporting "Nothing stalled." on failure.
              isEmpty={stalled.error === undefined && (stalled.data ?? []).length === 0}
            >
              {stalled.error !== undefined
                ? <ErrorState message={stalled.error} onRetry={stalled.reload} />
                : (stalled.data ?? []).map((p) => (
                  <Row key={p.clientModuleId} onClick={() => nav(`/clients/${p.clientId}?tab=modules`)}
                    title={p.clientName} sub={p.moduleName} />
                ))}
            </Card>

            <Card title="Follow-ups today" count={v.followUpsToday.length} empty="No follow-ups due." isEmpty={v.followUpsToday.length === 0}>
              {v.followUpsToday.map((f) => (
                <Row key={f.id} onClick={() => nav(`/clients/${f.clientId}`)}
                  title={f.clientName} sub={f.notes !== '' ? f.notes : '—'} />
              ))}
            </Card>

            <Card title="Recent payments" count={v.recentPayments.length} empty="No payments recorded yet." isEmpty={v.recentPayments.length === 0}>
              {v.recentPayments.map((p) => (
                <Row key={p.id} onClick={() => nav(`/clients/${p.clientId}`)}
                  title={p.clientName} sub={`${shortDate(p.receivedOn)} · ${p.mode}`}
                  right={inr(p.amountPaise)} />
              ))}
            </Card>
          </div>
        </>
      )}
    </div>
  )
}

/** One bento card: an uppercase-labelled header (+ count and optional link) over a
 *  scrollable list, or an empty-state line when there's nothing to show. */
function Card(props: {
  title: string; count?: number; link?: { to: string; label?: string }
  empty: string; isEmpty: boolean; children: ReactNode
}) {
  return (
    <section className="dash-card">
      <div className="dash-head">
        <h3>{props.title}</h3>
        {props.count !== undefined && <span className="count">{props.count}</span>}
        {props.link !== undefined && <Link to={props.link.to}>{props.link.label ?? 'All'} →</Link>}
      </div>
      {props.isEmpty ? <div className="dash-empty">{props.empty}</div> : <div className="dash-list">{props.children}</div>}
    </section>
  )
}

/** One list row — a title/sub on the left, an optional amount/sub on the right.
 *  Given `onClick`, it renders as a keyboard-operable <button>. */
function Row(props: {
  title: ReactNode; sub?: ReactNode; right?: ReactNode; rightSub?: ReactNode; onClick?: () => void
}) {
  const body = (
    <>
      <span className="rc">
        <span className="t">{props.title}</span>
        {props.sub !== undefined && <span className="s">{props.sub}</span>}
      </span>
      {(props.right !== undefined || props.rightSub !== undefined) && (
        <span className="r">
          {props.right !== undefined && <span className="amt">{props.right}</span>}
          {props.rightSub !== undefined && <span className="sub">{props.rightSub}</span>}
        </span>
      )}
    </>
  )
  return props.onClick !== undefined
    ? <button type="button" className="dash-row" onClick={props.onClick}>{body}</button>
    : <div className="dash-row">{body}</div>
}
