import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { formatINR } from '@sims/domain'
import { Badge, Button, ConfirmDialog, DataTable, EmptyState, ErrorState, FilterChips, Notice, PageHeader, Skeleton, Toolbar, useToast } from '@sims/ui'
import {
  documentAction, getEmployees, getPipeline, isManagerial,
  type Employee, type PipelineFilter, type PipelineRow, type PipelineStage,
} from '../api'
import { useData } from './Clients'

const PAGE_SIZE = 50

const STAGE_LABEL: Record<PipelineStage, string> = {
  enquiry: 'Enquiry', new_project: 'New Project', quoted_waiting: 'Quoted / Waiting',
  won: 'Won', lost: 'Lost',
}
const STAGE_TONE: Record<PipelineStage, 'ok' | 'warn' | 'err' | 'accent' | undefined> = {
  enquiry: undefined, new_project: 'warn', quoted_waiting: 'accent', won: 'ok', lost: 'err',
}
const ACTION_LABEL: Record<PipelineRow['nextAction'], string> = {
  send_quote: 'Send quote', waiting: 'Waiting', chase: 'Chase', nudge: 'Nudge',
  final_nudge: 'Final nudge', convert_invoice: 'Convert → invoice', none: '—',
}
/** Row tint mirrors the server-derived band (green < offset₁, amber, red ≥ last offset). */
const BAND_TONE = { green: 'ok', amber: 'warn', red: 'err' } as const

/**
 * Pipeline chase-list (spec §6b — D-PIPE option B): one cross-client ranked list,
 * most-overdue on top. Stage/age/next-action all derive server-side from the same
 * reminder_schedule offsets the follow-up engine uses; staff are server-forced to
 * their own rows, so the owner dropdown only renders for owner/manager.
 */
export function Pipeline() {
  const nav = useNavigate()
  const toast = useToast()
  const [filter, setFilter] = useState<PipelineFilter>('all')
  const [owner, setOwner] = useState('')
  const [page, setPage] = useState(1)
  const [error, setError] = useState<string | undefined>()
  // D18 WS-G: same one-click convert-and-send as the Documents register.
  const [converting, setConverting] = useState<{ docId: string; clientName: string } | undefined>()
  const managerial = isManagerial()

  const list = useData(
    () => getPipeline({ filter, ...(owner !== '' ? { owner } : {}), page, pageSize: PAGE_SIZE }),
    [filter, owner, page],
  )
  // Owner dropdown is a managerial-only widening control; staff never fetch the roster here.
  const employees = useData<{ employees: Employee[]; total: number } | undefined>(
    () => (managerial ? getEmployees() : Promise.resolve(undefined)), [],
  )

  const act = (p: Promise<unknown>) => {
    setError(undefined)
    p.then(() => list.reload()).catch((e: Error) => setError(e.message))
  }

  const actions = (r: PipelineRow) => {
    if (r.stage === 'enquiry') {
      return <Button onClick={() => nav('/documents/new')}>Send quote</Button>
    }
    if (r.stage === 'new_project') {
      return <Button onClick={() => nav(`/documents/${r.docId}`)}>Open draft</Button>
    }
    if (r.stage === 'quoted_waiting') {
      // Chase happens off-app (call/mail); the buttons record the outcome via the
      // existing lifecycle endpoint, then the list re-derives.
      return (
        <span style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
          <Button tone="primary" onClick={() => act(documentAction(r.docId!, 'status', { status: 'accepted' }))}>
            Accepted
          </Button>
          <Button tone="danger" onClick={() => act(documentAction(r.docId!, 'status', { status: 'lost' }))}>
            Lost
          </Button>
        </span>
      )
    }
    if (r.nextAction === 'convert_invoice') {
      return (
        <Button tone="primary" onClick={() => setConverting({ docId: r.docId!, clientName: r.clientName })}>
          Convert & send
        </Button>
      )
    }
    return null
  }

  const data = list.data
  const rows = data?.rows
  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="Pipeline"
        desc="Every open enquiry and quote, most overdue on top. Lost is hidden — use the filter to review it."
      />
      <Toolbar>
        <FilterChips
          chips={[
            { key: 'all', label: 'All' }, { key: 'mine', label: 'Mine' },
            { key: 'overdue', label: 'Overdue' }, { key: 'lost', label: 'Lost' },
          ]}
          active={filter}
          onChange={(k) => { setFilter(k as PipelineFilter); setPage(1) }}
        />
        {managerial && (
          <select
            className="wf" style={{ maxWidth: 200 }} value={owner} aria-label="Owner"
            onChange={(e) => { setOwner(e.target.value); setPage(1) }}
          >
            <option value="">Owner: everyone</option>
            {(employees.data?.employees ?? []).map((e) => (
              <option key={e.id} value={e.id}>{e.displayName}</option>
            ))}
          </select>
        )}
        {data !== undefined && (
          <Badge>chase after {data.dayOffsets.join(' / ')} days</Badge>
        )}
      </Toolbar>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
      {list.error !== undefined && <ErrorState message={list.error} onRetry={list.reload} />}
      {list.error !== undefined ? null
        : rows === undefined ? <Skeleton rows={6} />
        : rows.length === 0 ? <EmptyState>Nothing to chase — the pipeline is clear.</EmptyState> : (
        <>
          <DataTable
            columns={[
              { key: 'client', label: 'Client' },
              { key: 'amount', label: 'Amount', numeric: true },
              { key: 'owner', label: 'Owner' },
              { key: 'stage', label: 'Stage' },
              { key: 'age', label: 'Age', numeric: true },
              { key: 'next', label: 'Next action' },
              { key: 'actions', label: '' },
            ]}
            rowTone={(i) => {
              const band = rows[i]!.band
              return band !== null ? BAND_TONE[band] : undefined
            }}
            rows={rows.map((r) => ({
              client: (
                <Link to={`/clients/${r.clientId}`}>
                  {r.clientName}{r.stage === 'enquiry' ? ' (lead)' : ''}
                </Link>
              ),
              amount: r.amountPaise !== null ? formatINR(r.amountPaise) : '—',
              owner: r.ownerName ?? '—',
              stage: <Badge tone={STAGE_TONE[r.stage]}>{STAGE_LABEL[r.stage]}</Badge>,
              age: r.ageDays !== null ? `${r.ageDays}d` : '—',
              next: ACTION_LABEL[r.nextAction],
              actions: actions(r),
            }))}
          />
          {converting !== undefined && (
            <ConfirmDialog
              open
              onClose={() => setConverting(undefined)}
              onConfirm={() => documentAction(converting.docId, 'convert-and-send')
                .then((doc) => { toast.ok('Invoice issued & emailed'); nav(`/documents/${doc.id}`) })
                .catch((e: Error) => { setError(e.message); setConverting(undefined) })}
              title="Convert to invoice & send"
              body={`Convert the accepted proforma for ${converting.clientName} to a tax invoice, assign its number and email it to the client?`}
              confirmLabel="Convert & send"
            />
          )}
          <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>
        </>
      )}
    </div>
  )
}
