import { useEffect, useState } from 'react'
import { fromRupees } from '@sims/domain'
import { Button, Dialog, Field, FormField, FormGrid, Notice, Toolbar, useToast } from '@sims/ui'
import {
  createAmc, createInteraction, createRecurringPlan, patchClientModule, recordPayment,
  updateAmc, updateInteraction, updateRecurringPlan,
  CLIENT_MODULE_STATUSES, KIND_LABEL, PAYMENT_MODES,
  type AmcContract, type ClientModule, type ClientModuleStatus, type Employee, type Interaction,
  type InteractionType, type Kind, type Module, type PaymentMode, type RecurringPlan,
} from '../api'

const today = () => new Date().toISOString().slice(0, 10)

/**
 * Owner/manager only (server re-checks): pick the employee who owns this account,
 * so a lead with no quote is still routable to someone's queue. Writes client.owner_id
 * via the audited PATCH /clients/:id/owner. Inactive employees are hidden from the
 * picker, but a current owner who was since deactivated still renders.
 */
export function AccountOwnerSelect(props: {
  ownerId?: string; employees: Employee[]; onChange: (ownerId: string | null) => void
}) {
  return (
    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
      <span style={{ color: 'var(--muted, #6b7280)', fontSize: 13 }}>Account owner</span>
      <select
        className="wf" value={props.ownerId ?? ''}
        onChange={(e) => props.onChange(e.target.value !== '' ? e.target.value : null)}
      >
        <option value="">— unassigned —</option>
        {props.employees
          .filter((emp) => emp.active || emp.id === props.ownerId)
          .map((emp) => <option key={emp.id} value={emp.id}>{emp.displayName}</option>)}
      </select>
    </label>
  )
}

/** Owner-only: create or edit a recurring plan on one of the client's modules. */
export function PlanDialog(props: {
  open: boolean; onClose: () => void; clientId: string
  options: { id: string; label: string }[]; initial?: RecurringPlan; onDone: () => void
}) {
  const toast = useToast()
  const editing = props.initial !== undefined
  const [f, setF] = useState({ clientModuleId: '', cadence: 'monthly', amountRs: '', nextRun: today(), policy: 'manual' })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    const p = props.initial
    setError(undefined)
    setF({
      clientModuleId: p?.clientModuleId ?? '', cadence: p?.cadence ?? 'monthly',
      amountRs: p?.amountPaise !== null && p?.amountPaise !== undefined ? String(p.amountPaise / 100) : '',
      nextRun: p?.nextRun ?? today(), policy: p?.policy ?? 'manual',
    })
  }, [props.open, props.initial])

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

  const save = () => {
    if (saving) return
    if (!editing && f.clientModuleId === '') { setError('Pick a subscribed module'); return }
    const amount = f.amountRs === '' ? undefined : Number(f.amountRs)
    if (amount !== undefined && (!Number.isFinite(amount) || amount <= 0)) {
      setError('Amount must be a positive rupee value (or blank for the price book)'); return
    }
    setError(undefined)
    setSaving(true)
    const body = {
      cadence: f.cadence, nextRun: f.nextRun, policy: f.policy,
      // PATCH /recurring/:id cannot re-point a plan at another module, so edit mode
      // never sends clientModuleId (the select is disabled to match).
      ...(editing ? {} : { clientModuleId: f.clientModuleId }),
      // Edit mode: blank means "revert to price book" — send an explicit null so it clears.
      // Create mode: blank just omits the override, letting the price book resolve at generation time.
      ...(editing
        ? { amountPaise: amount !== undefined ? fromRupees(amount) : null }
        : amount !== undefined ? { amountPaise: fromRupees(amount) } : {}),
    }
    const call = editing ? updateRecurringPlan(props.initial!.id, body) : createRecurringPlan(props.clientId, body)
    call
      .then(() => { toast.ok('Plan saved'); props.onDone(); props.onClose() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title={editing ? 'Edit recurring plan' : 'New recurring plan'}
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" disabled={saving} onClick={save}>{saving ? 'Saving…' : editing ? 'Save changes' : 'New recurring plan'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Module">
          <select className="wf" autoFocus={!editing} value={f.clientModuleId} onChange={set('clientModuleId')} disabled={editing}>
            <option value="">Module…</option>
            {props.options.map((o) => <option key={o.id} value={o.id}>{o.label}</option>)}
          </select>
        </FormField>
        <FormField label="Cadence">
          <select className="wf" value={f.cadence} onChange={set('cadence')}>
            <option value="monthly">monthly</option>
            <option value="yearly">yearly</option>
          </select>
        </FormField>
        <FormField label="Amount (₹, optional)"><input className="wf num" value={f.amountRs} onChange={set('amountRs')} /></FormField>
        <FormField label="Next run"><input type="date" className="wf" value={f.nextRun} onChange={set('nextRun')} /></FormField>
        <FormField label="Policy">
          <select className="wf" value={f.policy} onChange={set('policy')}>
            <option value="manual">manual</option>
            <option value="auto">auto</option>
          </select>
        </FormField>
      </FormGrid>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}

/** Owner-only: create or edit an AMC contract — amount entered in rupees, stored in paise. */
export function AmcDialog(props: {
  open: boolean; onClose: () => void; clientId: string; initial?: AmcContract; onDone: () => void
}) {
  const toast = useToast()
  const editing = props.initial !== undefined
  const [f, setF] = useState({ coverage: '', periodFrom: today(), periodTo: '', amountRs: '', reminderDays: '30' })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    const a = props.initial
    setError(undefined)
    setF({
      coverage: a?.coverage ?? '', periodFrom: a?.periodFrom ?? today(), periodTo: a?.periodTo ?? '',
      amountRs: a !== undefined ? String(a.amountPaise / 100) : '',
      reminderDays: a !== undefined ? String(a.renewalReminderDays) : '30',
    })
  }, [props.open, props.initial])

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

  const save = () => {
    if (saving) return
    const amount = Number(f.amountRs)
    if (!Number.isFinite(amount) || amount <= 0) { setError('Enter the contract amount in rupees'); return }
    if (f.periodTo === '') { setError('Pick the period end date'); return }
    const days = Number(f.reminderDays)
    if (!Number.isInteger(days) || days < 0) { setError('Reminder days must be a non-negative integer'); return }
    setError(undefined)
    setSaving(true)
    const body = {
      coverage: f.coverage, periodFrom: f.periodFrom, periodTo: f.periodTo,
      amountPaise: fromRupees(amount), renewalReminderDays: days,
    }
    const call = editing ? updateAmc(props.initial!.id, body) : createAmc(props.clientId, body)
    call
      .then(() => { toast.ok('AMC saved'); props.onDone(); props.onClose() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title={editing ? 'Edit AMC contract' : 'New AMC contract'}
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" disabled={saving} onClick={save}>{saving ? 'Saving…' : editing ? 'Save changes' : 'New AMC'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Coverage" wide><input className="wf" autoFocus value={f.coverage} onChange={set('coverage')} /></FormField>
        <FormField label="Period from"><input type="date" className="wf" value={f.periodFrom} onChange={set('periodFrom')} /></FormField>
        <FormField label="Period to"><input type="date" className="wf" value={f.periodTo} onChange={set('periodTo')} /></FormField>
        <FormField label="Amount (₹)"><input className="wf num" value={f.amountRs} onChange={set('amountRs')} /></FormField>
        <FormField label="Reminder days"><input className="wf num" value={f.reminderDays} onChange={set('reminderDays')} /></FormField>
      </FormGrid>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}

/** All roles: log or edit a call / visit / training …; a follow-up date feeds the daily scan. */
export function InteractionDialog(props: {
  open: boolean; onClose: () => void; clientId: string
  types: InteractionType[]; initial?: Interaction; onDone: () => void
}) {
  const toast = useToast()
  const editing = props.initial !== undefined
  const [f, setF] = useState({ typeCode: '', onDate: today(), notes: '', outcome: '', followUpOn: '' })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (!props.open) return
    const i = props.initial
    setError(undefined)
    setF({
      typeCode: i?.typeCode ?? '', onDate: i?.onDate ?? today(), notes: i?.notes ?? '',
      outcome: i?.outcome ?? '', followUpOn: i?.followUpOn ?? '',
    })
  }, [props.open, props.initial])

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

  const save = () => {
    if (saving) return
    if (f.typeCode === '') { setError('Pick an interaction type'); return }
    setError(undefined)
    setSaving(true)
    const body = {
      notes: f.notes,
      // PATCH /interactions/:id cannot change type or date, so edit mode never sends
      // typeCode/onDate (the fields are disabled to match) — a silently-ignored
      // "correction" with a success toast is worse than a locked field.
      ...(editing ? {} : { typeCode: f.typeCode, onDate: f.onDate }),
      // Edit mode: blank means "clear it" — send an explicit null so the server clears the column
      // (same semantics as ClientDetail's inline follow-up quick-edit). Create mode omits when blank.
      ...(editing
        ? { outcome: f.outcome !== '' ? f.outcome : null, followUpOn: f.followUpOn !== '' ? f.followUpOn : null }
        : {
            ...(f.outcome !== '' ? { outcome: f.outcome } : {}),
            ...(f.followUpOn !== '' ? { followUpOn: f.followUpOn } : {}),
          }),
    }
    const call = editing ? updateInteraction(props.initial!.id, body) : createInteraction(props.clientId, body)
    call
      .then(() => { toast.ok('Interaction saved'); props.onDone(); props.onClose() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <Dialog
      open={props.open}
      onClose={() => { if (!saving) props.onClose() }}
      title={editing ? 'Edit interaction' : 'Log interaction'}
      footer={
        <>
          <Button pill onClick={() => { if (!saving) props.onClose() }}>Cancel</Button>
          <Button pill tone="primary" disabled={saving} onClick={save}>{saving ? (editing ? 'Saving…' : 'Logging…') : editing ? 'Save changes' : 'Log interaction'}</Button>
        </>
      }
    >
      <FormGrid>
        <FormField label="Type">
          <select className="wf" autoFocus={!editing} value={f.typeCode} onChange={set('typeCode')} disabled={editing}>
            <option value="">Type…</option>
            {props.types.map((t) => <option key={t.code} value={t.code}>{t.label}</option>)}
          </select>
        </FormField>
        <FormField label="On"><input type="date" className="wf" value={f.onDate} onChange={set('onDate')} disabled={editing} /></FormField>
        <FormField label="Outcome">
          <select className="wf" value={f.outcome} onChange={set('outcome')}>
            <option value="">—</option>
            <option value="positive">positive</option>
            <option value="neutral">neutral</option>
            <option value="negative">negative</option>
          </select>
        </FormField>
        <FormField label="Follow-up on"><input type="date" className="wf" value={f.followUpOn} onChange={set('followUpOn')} /></FormField>
        <FormField label="Notes" wide><textarea className="wf" rows={2} value={f.notes} onChange={set('notes')} /></FormField>
      </FormGrid>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </Dialog>
  )
}

export function AssignModuleForm(props: { modules: Module[]; onAssign: (moduleId: string, kind: Kind) => void }) {
  const [moduleId, setModuleId] = useState('')
  const mod = props.modules.find((m) => m.id === moduleId)
  const [kind, setKind] = useState<Kind | ''>('')
  return (
    <Toolbar>
      <select
        className="wf" value={moduleId}
        onChange={(e) => { setModuleId(e.target.value); setKind('') }}
      >
        <option value="">Assign module…</option>
        {props.modules.filter((m) => m.active).map((m) => <option key={m.id} value={m.id}>{m.name}</option>)}
      </select>
      {mod !== undefined && (
        <select className="wf" value={kind} onChange={(e) => setKind(e.target.value as Kind)}>
          <option value="">Kind…</option>
          {mod.allowedKinds.map((k) => <option key={k} value={k}>{KIND_LABEL[k]}</option>)}
        </select>
      )}
      <Button
        tone="primary"
        onClick={() => { if (moduleId !== '' && kind !== '') { props.onAssign(moduleId, kind); setModuleId(''); setKind('') } }}
      >
        Assign
      </Button>
    </Toolbar>
  )
}

export function ClientModuleStatusSelect(props: {
  cm: ClientModule; onPatched: () => void; onError: (msg: string) => void
}) {
  return (
    <select
      className="wf" value={props.cm.status}
      onChange={(e) => {
        patchClientModule(props.cm.id, { status: e.target.value as ClientModuleStatus })
          .then(props.onPatched).catch((err: Error) => props.onError(err.message))
      }}
    >
      {CLIENT_MODULE_STATUSES.map((s) => <option key={s} value={s}>{s}</option>)}
    </select>
  )
}

export function RowDate(props: {
  cm: ClientModule; field: 'installedOn' | 'completedOn' | 'trainedOn'
  onPatched: () => void; onError: (msg: string) => void
}) {
  return (
    <input
      type="date" className="wf" style={{ width: 140 }}
      value={props.cm[props.field] ?? ''}
      onChange={(e) => {
        patchClientModule(props.cm.id, { [props.field]: e.target.value !== '' ? e.target.value : null })
          .then(props.onPatched).catch((err: Error) => props.onError(err.message))
      }}
    />
  )
}

/**
 * Record a payment against the client — amounts entered in rupees, stored in
 * integer paise via fromRupees. Shared with DocumentView's "Record payment".
 */
export function PaymentForm(props: { clientId: string; onDone: () => void }) {
  const [f, setF] = useState({ amountRs: '', tdsRs: '', mode: 'bank' as PaymentMode, reference: '', receivedOn: today() })
  const [error, setError] = useState<string | undefined>()
  const [saving, setSaving] = useState(false)
  const set = (k: keyof typeof f) => (e: { target: { value: string } }) =>
    setF((p) => ({ ...p, [k]: e.target.value }))

  const save = () => {
    const amount = Number(f.amountRs)
    if (!Number.isFinite(amount) || amount <= 0) { setError('Enter a payment amount in rupees'); return }
    const tds = f.tdsRs === '' ? 0 : Number(f.tdsRs)
    if (!Number.isFinite(tds) || tds < 0) { setError('TDS must be a non-negative rupee amount'); return }
    setError(undefined)
    setSaving(true)
    recordPayment({
      clientId: props.clientId, receivedOn: f.receivedOn, mode: f.mode, reference: f.reference,
      amountPaise: fromRupees(amount), tdsPaise: fromRupees(tds),
    })
      .then(() => { setF({ amountRs: '', tdsRs: '', mode: 'bank', reference: '', receivedOn: today() }); props.onDone() })
      .catch((e: Error) => setError(e.message))
      .finally(() => setSaving(false))
  }

  return (
    <div className="wf-card">
      <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'flex-end' }}>
        <Field label="Amount (₹)"><input className="wf num" style={{ width: 120 }} value={f.amountRs} onChange={set('amountRs')} /></Field>
        <Field label="TDS (₹)"><input className="wf num" style={{ width: 100 }} value={f.tdsRs} onChange={set('tdsRs')} /></Field>
        <Field label="Mode">
          <select className="wf" value={f.mode} onChange={set('mode')}>
            {PAYMENT_MODES.map((m) => <option key={m} value={m}>{m}</option>)}
          </select>
        </Field>
        <Field label="Reference"><input className="wf" value={f.reference} onChange={set('reference')} /></Field>
        <Field label="Received on"><input type="date" className="wf" value={f.receivedOn} onChange={set('receivedOn')} /></Field>
        <Button tone="primary" disabled={saving} onClick={save}>{saving ? 'Recording…' : 'Record payment'}</Button>
      </div>
      {error !== undefined && <Notice tone="err">{error}</Notice>}
    </div>
  )
}
