import { useEffect, useMemo, useState } from 'react'
import { formatINR, fromRupees } from '@sims/domain'
import {
  Badge, Button, DataTable, Dialog, EmptyState, ErrorState, Field, FormField, FormGrid, Notice,
  PageHeader, Skeleton, Toolbar, useToast,
} from '@sims/ui'
import {
  addPrice, createModule, downloadModuleClientsCsv, getModuleClients, getModules, getPrices,
  notifyModuleClients, patchModule, previewSample, role,
  KIND_LABEL, type Kind, type Module,
} from '../api'
import { LivePreview } from '../components/LivePreview'
import { useData } from './Clients'

const ALL_KINDS: Kind[] = ['one_time', 'monthly', 'yearly', 'usage']
const today = () => new Date().toISOString().slice(0, 10)

/** Textarea ↔ string[]: one "what's included" bullet per row, blanks dropped. */
const splitLines = (s: string): string[] => s.split('\n').map((x) => x.trim()).filter((x) => x !== '')

/** Module catalog + dated price book. Owner edits; staff read-only. */
export function Modules() {
  const isOwner = role() === 'owner'
  const modules = useData(getModules, [])
  const [creating, setCreating] = useState(false)
  const [selected, setSelected] = useState<Module | undefined>()

  return (
    <div className="wf-page">
      <PageHeader
        title="Modules"
        desc="What we sell — each with a dated price book (later rows win from their effective date)."
        actions={isOwner
          ? <Button tone="primary" onClick={() => setCreating(true)}>New module</Button>
          : <Badge>read-only (staff)</Badge>}
      />
      {modules.error !== undefined ? <ErrorState message={modules.error} onRetry={modules.reload} />
        : modules.data === undefined ? <Skeleton rows={5} />
        : modules.data.length === 0 ? <EmptyState>No modules yet.</EmptyState> : (
        <DataTable
          columns={[
            { key: 'code', label: 'Code', mono: true }, { key: 'name', label: 'Name' },
            { key: 'sac', label: 'SAC' }, { key: 'kinds', label: 'Billing kinds' },
            { key: 'multi', label: 'Multi-sub' }, { key: 'active', label: 'Active' },
          ]}
          onRowClick={(_row, i) => setSelected(modules.data![i])}
          rows={modules.data.map((m) => ({
            code: m.code, name: m.name, sac: m.sac,
            kinds: m.allowedKinds.map((k) => KIND_LABEL[k]).join(' · '),
            multi: m.multiSubscription ? <Badge tone="accent">yes</Badge> : '—',
            active: m.active ? <Badge tone="ok">active</Badge> : <Badge>inactive</Badge>,
          }))}
        />
      )}
      {selected !== undefined && (
        <>
          <ModuleClients key={`mc-${selected.id}`} module={selected} />
          <QuoteContent key={selected.id} module={selected} isOwner={isOwner} onSaved={() => modules.reload()} />
          <PriceBook module={selected} isOwner={isOwner} />
        </>
      )}
      {isOwner && (
        <NewModuleDialog
          open={creating}
          onClose={() => setCreating(false)}
          onCreated={() => { setCreating(false); modules.reload() }}
        />
      )}
    </div>
  )
}

/**
 * "Who's on this module" roster (spec §10): every ACTIVE client link with what
 * it pays and its next renewal, plus Notify-all (owner/manager) and CSV export.
 */
function ModuleClients(props: { module: Module }) {
  const managerial = role() === 'owner' || role() === 'manager'
  const [page, setPage] = useState(1)
  const roster = useData(() => getModuleClients(props.module.id, page), [props.module.id, page])
  const [notifying, setNotifying] = useState(false)
  const [subject, setSubject] = useState('')
  const [bodyText, setBodyText] = useState('')
  const [busy, setBusy] = useState(false)
  const [result, setResult] = useState<string | undefined>()
  const [err, setErr] = useState<string | undefined>()

  const doNotify = () => {
    setBusy(true); setErr(undefined); setResult(undefined)
    notifyModuleClients(props.module.id, { subject, body: bodyText })
      .then((out) => {
        setResult(`Sent ${out.sent}/${out.total}`
          + (out.failed.length > 0 ? ` — unreached: ${out.failed.map((f) => `${f.client} (${f.error})`).join(', ')}` : ''))
        setNotifying(false)
      })
      .catch((e: Error) => setErr(e.message))
      .finally(() => setBusy(false))
  }

  const data = roster.data
  const pages = data !== undefined ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1
  return (
    <section>
      <h2>Clients on this module</h2>
      <Toolbar>
        {managerial && (
          <Button onClick={() => setNotifying((v) => !v)}>
            {notifying ? 'Close composer' : `Notify all${data !== undefined ? ` (${data.total})` : ''}`}
          </Button>
        )}
        <Button onClick={() => { downloadModuleClientsCsv(props.module.id, props.module.code).catch((e: Error) => setErr(e.message)) }}>
          Export CSV
        </Button>
      </Toolbar>
      {notifying && managerial && (
        <div className="wf-form">
          <Field label="Subject"><input value={subject} onChange={(e) => setSubject(e.target.value)} /></Field>
          <Field label="Message">
            <textarea rows={4} value={bodyText} onChange={(e) => setBodyText(e.target.value)} />
          </Field>
          <Button
            tone="primary"
            onClick={() => { if (!busy && subject.trim() !== '' && bodyText.trim() !== '') doNotify() }}
          >
            {busy ? 'Sending…' : `Send to every client on ${props.module.code}`}
          </Button>
        </div>
      )}
      {result !== undefined && <Notice tone="ok">{result}</Notice>}
      {err !== undefined && <Notice tone="err">{err}</Notice>}
      {roster.error !== undefined ? <ErrorState message={roster.error} onRetry={roster.reload} />
        : data === undefined ? <Skeleton rows={4} />
        : data.total === 0 ? <EmptyState>No client is on this module yet.</EmptyState> : (
        <>
          <DataTable
            columns={[
              { key: 'client', label: 'Client' }, { key: 'code', label: 'Code', mono: true },
              { key: 'status', label: 'Status' }, { key: 'kindEdition', label: 'Kind · Edition' },
              { key: 'pays', label: 'Pays' }, { key: 'renewal', label: 'Next renewal' },
            ]}
            rows={data.clients.map((c) => ({
              client: c.clientName, code: c.clientCode,
              status: <Badge tone={c.status === 'live' ? 'ok' : undefined}>{c.status}</Badge>,
              kindEdition: `${KIND_LABEL[c.kind]} · ${c.edition}`,
              pays: c.pricePaise !== null ? formatINR(c.pricePaise) : '—',
              renewal: c.nextRenewal ?? '—',
            }))}
          />
          <div className="wf-pager">
            <span>{data.total} client(s) · total {formatINR(data.totalPricePaise)} at current price book</span>
            {pages > 1 && (
              <>
                <Button onClick={() => { if (page > 1) setPage((p) => p - 1) }}>‹ Prev</Button>
                <span>Page {data.page}/{pages}</span>
                <Button onClick={() => { if (page < pages) setPage((p) => p + 1) }}>Next ›</Button>
              </>
            )}
          </div>
        </>
      )}
    </section>
  )
}

/** Per-module "what's included" lines — prefilled into the composer, printed under the quote line. */
function QuoteContent(props: { module: Module; isOwner: boolean; onSaved: () => void }) {
  const toast = useToast()
  const [text, setText] = useState(props.module.quoteContent.join('\n'))
  const [error, setError] = useState<string | undefined>()
  const [commitNonce, setCommitNonce] = useState(0)
  const previewBody = useMemo(() => JSON.stringify({ contentLines: splitLines(text) }), [text])

  const save = () => {
    setError(undefined)
    patchModule(props.module.id, { quoteContent: splitLines(text) })
      .then(() => { toast.ok('Quote content saved'); props.onSaved() })
      .catch((e: Error) => setError(e.message))
  }

  return (
    <>
      <h3 style={{ marginTop: 20 }}>Quote content — {props.module.name}</h3>
      {props.isOwner ? (
        <div style={{ display: 'flex', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
          <div style={{ flex: '0 0 560px', minWidth: 0 }}>
            <textarea className="wf" rows={4} placeholder="One included item per line…"
              value={text} onChange={(e) => setText(e.target.value)} onBlur={() => setCommitNonce((n) => n + 1)} />
            <Toolbar>
              <Button tone="primary" onClick={save}>Save quote content</Button>
            </Toolbar>
            {error !== undefined && <Notice tone="err">{error}</Notice>}
          </div>
          <div style={{ flex: 1, minWidth: 320, height: 420, background: 'var(--bg-inset)', borderRadius: 8, padding: 12 }}>
            <div style={{ width: '100%', height: '100%', background: '#fff', borderRadius: 4, boxShadow: '0 1px 6px rgba(0,0,0,.15)', overflow: 'hidden' }}>
              <LivePreview
                body={previewBody}
                commitNonce={commitNonce}
                fetchPreview={(b, signal) => previewSample(JSON.parse(b), signal).then((r) => ({ html: r.html }))}
              />
            </div>
          </div>
        </div>
      ) : props.module.quoteContent.length === 0 ? (
        <EmptyState>No quote content.</EmptyState>
      ) : (
        <ul>{props.module.quoteContent.map((line, i) => <li key={i}>{line}</li>)}</ul>
      )}
    </>
  )
}

function NewModuleDialog(props: { open: boolean; onClose: () => void; onCreated: () => void }) {
  const toast = useToast()
  const [f, setF] = useState({ code: '', name: '', sac: '998313' })
  const [kinds, setKinds] = useState<Kind[]>([...ALL_KINDS])
  const [multi, setMulti] = useState(false)
  const [quoteText, setQuoteText] = useState('')
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    setError(undefined)
    setF({ code: '', name: '', sac: '998313' })
    setKinds([...ALL_KINDS])
    setMulti(false)
    setQuoteText('')
  }, [props.open])

  const set = (k: keyof typeof f) => (e: { target: { value: string } }) =>
    setF((p) => ({ ...p, [k]: e.target.value }))
  const toggleKind = (k: Kind) =>
    setKinds((prev) => (prev.includes(k) ? prev.filter((x) => x !== k) : [...prev, k]))

  const save = () => {
    if (saving) return
    if (f.code.trim() === '' || f.name.trim() === '') { setError('Code and name are required'); return }
    if (kinds.length === 0) { setError('Pick at least one billing kind'); return }
    setError(undefined)
    setSaving(true)
    createModule({
      code: f.code.trim().toUpperCase(), name: f.name.trim(), sac: f.sac.trim(),
      allowedKinds: ALL_KINDS.filter((k) => kinds.includes(k)), multiSubscription: multi,
      quoteContent: splitLines(quoteText),
    })
      .then(() => { toast.ok('Module created'); props.onCreated() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title="New module"
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" onClick={save}>{saving ? 'Saving…' : 'Save module'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Code"><input className="wf" value={f.code} autoFocus onChange={set('code')} /></FormField>
        <FormField label="Name"><input className="wf" value={f.name} onChange={set('name')} /></FormField>
        <FormField label="SAC"><input className="wf" value={f.sac} onChange={set('sac')} /></FormField>
        <FormField label="Billing kinds">
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            {ALL_KINDS.map((k) => (
              <label key={k} style={{ display: 'flex', gap: 4, alignItems: 'center', fontSize: 13 }}>
                <input type="checkbox" checked={kinds.includes(k)} onChange={() => toggleKind(k)} />
                {KIND_LABEL[k]}
              </label>
            ))}
          </div>
        </FormField>
        <FormField label="Multi-subscription">
          <label style={{ display: 'flex', gap: 4, alignItems: 'center', fontSize: 13 }}>
            <input type="checkbox" checked={multi} onChange={() => setMulti((v) => !v)} />
            multi-subscription
          </label>
        </FormField>
        <FormField label="Quote content (one per line, optional)" wide>
          <textarea className="wf" rows={3} value={quoteText} onChange={(e) => setQuoteText(e.target.value)} />
        </FormField>
      </FormGrid>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}

function PriceBook(props: { module: Module; isOwner: boolean }) {
  const prices = useData(() => getPrices(props.module.id), [props.module.id])
  const [adding, setAdding] = useState(false)

  return (
    <>
      <h3 style={{ marginTop: 20 }}>Prices — {props.module.name}</h3>
      {props.isOwner && (
        <Toolbar>
          <Button tone="primary" onClick={() => setAdding(true)}>Add price</Button>
        </Toolbar>
      )}
      {prices.error !== undefined ? <ErrorState message={prices.error} onRetry={prices.reload} />
        : prices.data === undefined ? <Skeleton rows={5} />
        : prices.data.length === 0 ? <EmptyState>No prices yet{props.isOwner ? ' — add the first one above' : ''}.</EmptyState> : (
        <DataTable
          columns={[
            { key: 'kind', label: 'Kind' }, { key: 'edition', label: 'Edition' },
            { key: 'price', label: 'Price', numeric: true }, { key: 'from', label: 'Effective from' },
          ]}
          rows={prices.data.map((p) => ({
            kind: KIND_LABEL[p.kind], edition: p.edition,
            price: formatINR(p.pricePaise), from: p.effectiveFrom,
          }))}
        />
      )}
      {props.isOwner && (
        <AddPriceDialog
          open={adding}
          onClose={() => setAdding(false)}
          module={props.module}
          onAdded={() => { setAdding(false); prices.reload() }}
        />
      )}
    </>
  )
}

function AddPriceDialog(props: { open: boolean; onClose: () => void; module: Module; onAdded: () => void }) {
  const toast = useToast()
  const [f, setF] = useState({ kind: '' as Kind | '', edition: 'standard', priceRs: '', effectiveFrom: today() })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    setError(undefined)
    setF({ kind: '', edition: 'standard', priceRs: '', effectiveFrom: today() })
  }, [props.open, props.module.id])

  const set = (k: keyof typeof f) => (e: { target: { value: string } }) =>
    setF((p) => ({ ...p, [k]: e.target.value }))

  const save = () => {
    if (saving) return
    const rs = Number(f.priceRs)
    if (f.kind === '') { setError('Pick a kind'); return }
    if (!Number.isFinite(rs) || rs < 0) { setError('Enter the price in rupees'); return }
    setError(undefined)
    setSaving(true)
    addPrice(props.module.id, {
      kind: f.kind, edition: f.edition.trim() !== '' ? f.edition.trim() : 'standard',
      pricePaise: fromRupees(rs), effectiveFrom: f.effectiveFrom,
    })
      .then(() => { toast.ok('Price added'); props.onAdded() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title={`Add price — ${props.module.name}`}
      size="sm"
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" onClick={save}>{saving ? 'Saving…' : 'Add price'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Kind">
          <select className="wf" autoFocus value={f.kind} onChange={set('kind')}>
            <option value="">Kind…</option>
            {props.module.allowedKinds.map((k) => <option key={k} value={k}>{KIND_LABEL[k]}</option>)}
          </select>
        </FormField>
        <FormField label="Edition"><input className="wf" value={f.edition} onChange={set('edition')} /></FormField>
        <FormField label="Price (₹)"><input className="wf num" value={f.priceRs} onChange={set('priceRs')} /></FormField>
        <FormField label="Effective from"><input type="date" className="wf" value={f.effectiveFrom} onChange={set('effectiveFrom')} /></FormField>
      </FormGrid>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}
