import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { MasterDetail } from '@/components/templates'
import {
  Badge,
  ConfirmDialog,
  EmptyState,
  Input,
  Select,
  useToast,
  type Column,
} from '@/components/ui'
import { serverMessage } from '@/lib/api'
import { groupDigits, placeSymbol, currencySymbol as suggestedSymbolFor, type CurrencyPosition } from '@/lib/money'
import {
  useCrudPanel,
  useCreateCurrency,
  useDeleteCurrency,
  useCurrencies,
  useUpdateCurrency,
  type Currency,
} from '../hooks'

type Draft = {
  name: string
  code: string
  symbol: string
  decimals: number
  position: CurrencyPosition
  thousand_separator: string
  decimal_separator: string
}

// The reference codebase's own `AddCurrency::mount()` defaults, verbatim.
const empty: Draft = { name: '', code: '', symbol: '', decimals: 2, position: 'left', thousand_separator: ',', decimal_separator: '.' }

/** The reference codebase's four position options, labelled here rather than as raw values. */
const POSITIONS: { value: CurrencyPosition; label: string }[] = [
  { value: 'left', label: 'Left' },
  { value: 'right', label: 'Right' },
  { value: 'left_with_space', label: 'Left, with a space' },
  { value: 'right_with_space', label: 'Right, with a space' },
]

/**
 * Currencies — a store's own list (Settings → Currencies), independent of the
 * platform's catalogue (superadmin-only). Add/edit/delete here; which one is
 * ACTIVE is set from Settings → Store profile, not from this page — the same
 * separation the reference codebase itself uses (its Currency-list screen
 * has no default-picker either).
 *
 * `decimals` is required on Add because it is the one fact the money engine
 * cannot infer for a currency it has never seen before — Money.php / money.ts
 * both read it off this store's own row before falling back to a small
 * built-in table. `position`/`thousand_separator`/`decimal_separator` are
 * the reference codebase's own money-formatting fields, ported verbatim on
 * instruction — lib/money.ts's `groupDigits`/`placeSymbol` build every
 * amount from these, the same shape the reference codebase's
 * `currency_format()` helper does with PHP's `number_format()`.
 */
export default function CurrenciesPage() {
  const { t } = useTranslation()
  const toast = useToast()

  const { data, isLoading } = useCurrencies()
  const create = useCreateCurrency()
  const update = useUpdateCurrency()
  const del = useDeleteCurrency()

  const panel = useCrudPanel<Currency, Draft>(empty, (c) => ({
    name: c.name,
    code: c.code,
    symbol: c.symbol,
    decimals: c.decimals,
    position: c.position,
    thousand_separator: c.thousand_separator ?? '',
    decimal_separator: c.decimal_separator ?? '.',
  }))
  const [confirmDelete, setConfirmDelete] = useState(false)

  const d = panel.draft

  // Suggests the locale-correct symbol the moment a real ISO code is typed —
  // still freely editable, since a shop naming a currency the platform has
  // never heard of needs to type its own (Intl falls back to the bare code
  // for one it does not recognise).
  const onCodeChange = (raw: string) => {
    const code = raw.toUpperCase().slice(0, 3)
    const suggestion = code.length === 3 ? suggestedSymbolFor(code) : ''
    panel.patch({ code, symbol: !d.symbol || d.symbol === suggestedSymbolFor(d.code) ? suggestion : d.symbol })
  }

  // The exact string a save would produce right now — never a separate
  // description that could drift from what money.ts actually does, since it
  // calls the very same two functions.
  const sample = (position: CurrencyPosition) =>
    placeSymbol(groupDigits(1234.5, d.decimals, d.decimal_separator, d.thousand_separator), d.symbol || d.code || '$', position)

  const save = () => {
    if (!d.name.trim()) {
      toast.danger(t('Name required'), t('Give the currency a name, e.g. "US Dollar".'))
      return
    }
    if (d.code.length !== 3) {
      toast.danger(t('Code required'), t('A three-letter code, e.g. USD.'))
      return
    }
    if (!d.symbol.trim()) {
      toast.danger(t('Symbol required'), t('e.g. $, £, ₹.'))
      return
    }

    const input = {
      name: d.name.trim(),
      code: d.code,
      symbol: d.symbol.trim(),
      decimals: d.decimals,
      position: d.position,
      thousand_separator: d.thousand_separator,
      decimal_separator: d.decimal_separator,
    }

    const onError = (e: unknown) =>
      toast.danger(t('Could not save'), serverMessage(e, t('Please try again.')))
    const onSuccess = () => {
      toast.success(t('Currency saved'), t('{{name}} was saved', { name: input.name }))
      panel.close()
    }

    if (panel.isNew) create.mutate(input, { onSuccess, onError })
    else update.mutate({ id: panel.editing!.id, input }, { onSuccess, onError })
  }

  const columns: Column<Currency>[] = [
    {
      key: 'name',
      header: t('Currency'),
      cell: (c) => (
        <div className="flex items-center gap-2">
          <b className="text-content">{c.name}</b>
          {c.is_default && <Badge tone="accent">{t('Active')}</Badge>}
        </div>
      ),
    },
    { key: 'code', header: t('Code'), cell: (c) => <span className="mono text-content-2">{c.code}</span> },
    { key: 'symbol', header: t('Symbol'), cell: (c) => <span className="text-content-2">{c.symbol}</span> },
    { key: 'decimals', header: t('Decimals'), cell: (c) => <span className="text-content-2">{c.decimals}</span> },
    {
      key: 'sample',
      header: t('Example'),
      cell: (c) => (
        <span className="mono text-content-2">
          {placeSymbol(groupDigits(1234.5, c.decimals, c.decimal_separator ?? '.', c.thousand_separator ?? ','), c.symbol, c.position)}
        </span>
      ),
    },
  ]

  return (
    <>
      <MasterDetail<Currency>
        writePermission="Manage Settings"
        title={t('Currencies')}
        microcopy={t('The currencies this store trades in. Add one here, then make it active from Settings → Store profile.')}
        addLabel={t('Add currency')}
        onAdd={() => panel.openNew()}
        loading={isLoading}
        columns={columns}
        rows={data ?? []}
        rowKey={(c) => String(c.id)}
        onRowClick={panel.openEdit}
        isRowActive={(c) => c.id === panel.editing?.id}
        emptyState={
          <EmptyState
            icon="cash"
            title={t('No currencies yet')}
            description={t('Add the currencies this store trades in — then pick the active one on Settings → Store profile.')}
          />
        }
        detailOpen={panel.open}
        onCloseDetail={panel.close}
        detailTitle={panel.isNew ? t('New currency') : panel.editing?.name}
        detailSubtitle={t('currency')}
        dirty={panel.dirty}
        saving={create.isPending || update.isPending}
        onSave={save}
        onDiscard={panel.close}
        onDelete={panel.editing ? () => setConfirmDelete(true) : undefined}
        detail={
          <div className="grid gap-4">
            <Input
              label={t('Name')}
              required
              value={d.name}
              onChange={(e) => panel.patch({ name: e.target.value })}
              placeholder={t('e.g. US Dollar')}
            />
            <Input
              label={t('Code')}
              required
              mono
              value={d.code}
              onChange={(e) => onCodeChange(e.target.value)}
              placeholder="USD"
              help={t('Three letters. Not checked against a registry — a currency the platform has never heard of is fine.')}
            />
            <Input
              label={t('Symbol')}
              required
              value={d.symbol}
              onChange={(e) => panel.patch({ symbol: e.target.value })}
              placeholder="$"
            />
            <Input
              label={t('Decimal places')}
              required
              type="number"
              min={0}
              max={4}
              value={String(d.decimals)}
              onChange={(e) => panel.patch({ decimals: Math.max(0, Math.min(4, Number(e.target.value) || 0)) })}
              help={t('How many digits after the point — 2 for most currencies, 0 for Yen, 3 for Dinar.')}
            />
            <Select
              label={t('Symbol position')}
              value={d.position}
              onChange={(e) => panel.patch({ position: e.target.value as CurrencyPosition })}
              options={POSITIONS.map((p) => ({ value: p.value, label: `${t(p.label)} — ${sample(p.value)}` }))}
            />
            <div className="grid gap-4 sm:grid-cols-2">
              <Input
                label={t('Thousand separator')}
                value={d.thousand_separator}
                onChange={(e) => panel.patch({ thousand_separator: e.target.value })}
                placeholder=","
                maxLength={8}
                help={t('Leave blank for no digit grouping at all.')}
              />
              <Input
                label={t('Decimal separator')}
                value={d.decimal_separator}
                onChange={(e) => panel.patch({ decimal_separator: e.target.value })}
                placeholder="."
                maxLength={8}
              />
            </div>
            <div className="rounded-ctl border border-border bg-surface-2 px-3 py-2">
              <span className="text-xs text-content-3">{t('Example')}</span>
              <div className="mono text-lg font-semibold text-content">{sample(d.position)}</div>
            </div>
          </div>
        }
      />

      <ConfirmDialog
        open={confirmDelete}
        onClose={() => setConfirmDelete(false)}
        title={t('Delete this currency?')}
        consequence={t('This can\'t be undone. Refused if it\'s the store\'s active currency — make another one active first (Settings → Store profile).')}
        confirmLabel={t('Delete')}
        onConfirm={() =>
          del.mutate({ id: panel.editing!.id }, {
            onSuccess: () => {
              toast.success(t('Currency deleted'))
              setConfirmDelete(false)
              panel.close()
            },
            onError: (e) => {
              setConfirmDelete(false)
              toast.danger(t('Could not delete'), serverMessage(e, t('Please try again.')))
            },
          })
        }
      />
    </>
  )
}
