import { useState, useEffect, useRef } from 'react'
import { RefreshCw, Save, CheckCircle, Loader, Camera, FileText, X } from 'lucide-react'
import { api, uploadAttachment } from '../api'
import { PageHeader, Card, Btn, StatusBadge } from '../components/Layout'
import {
  GBP_DENOMINATIONS, fmtGBP, today, can,
  type User, type CashUp, type Denomination, type CardMachine,
  type PaymentTotals, type ReconciliationRow, type TillPayment, type Attachment,
  type TransactionBreakdown, type TransactionItem,
} from '../types'

const MACHINES = ['Front Desk', 'Restaurant / Bar']

function initDenominations(countType: 'takings' | 'float'): Denomination[] {
  return GBP_DENOMINATIONS.map(d => ({
    count_type: countType,
    denomination_type: d.type,
    denomination_value: d.value,
    quantity: null,
    value_entered: null,
    total_amount: 0,
  }))
}

function initMachines(): CardMachine[] {
  return MACHINES.map(name => ({ machine_name: name, total_amount: 0, amex_amount: 0, visa_mc_amount: 0 }))
}

function denomTotal(denoms: Denomination[]) {
  return denoms.reduce((s, d) => s + (Number(d.total_amount) || 0), 0)
}

interface Props { user: User }

// flow: checking → empty (no record) | editing (draft) | locked (final)
type PageState = 'checking' | 'empty' | 'editing' | 'locked'

export function DailyCashUp({ user }: Props) {
  const canFinalise = can(user, 'finalise')
  const [date, setDate] = useState(today())
  const [pageState, setPageState] = useState<PageState>('checking')
  const [cashUp, setCashUp] = useState<CashUp | null>(null)
  const [takings, setTakings] = useState<Denomination[]>(initDenominations('takings'))
  const [float, setFloat] = useState<Denomination[]>(initDenominations('float'))
  const [machines, setMachines] = useState<CardMachine[]>(initMachines())
  const [notes, setNotes] = useState('')
  const [attachments, setAttachments] = useState<Attachment[]>([])
  const [newbookTotals, setNewbookTotals] = useState<PaymentTotals | null>(null)
  const [tillPayments, setTillPayments] = useState<TillPayment[]>([])
  const [transactionBreakdown, setTransactionBreakdown] = useState<TransactionBreakdown | null>(null)
  const [checkedItems, setCheckedItems] = useState<Set<string>>(new Set())
  const [fetching, setFetching] = useState(false)
  const [saving, setSaving] = useState(false)
  const [msg, setMsg] = useState<{ text: string; ok: boolean } | null>(null)
  const [showFloat, setShowFloat] = useState(false)

  const isFinal = pageState === 'locked'

  function flash(text: string, ok = true) {
    setMsg({ text, ok })
    setTimeout(() => setMsg(null), 4000)
  }

  function applyLoaded(data: {
    cash_up: CashUp; denominations: Denomination[]; card_machines: CardMachine[]; attachments: Attachment[]
  }) {
    setCashUp(data.cash_up)
    setNotes(data.cash_up.notes || '')
    setAttachments(data.attachments || [])

    const rebuild = (ct: 'takings' | 'float') =>
      GBP_DENOMINATIONS.map(d => {
        const saved = data.denominations.find(
          s => s.count_type === ct && parseFloat(String(s.denomination_value)) === d.value
        )
        return saved
          ? {
              ...saved,
              denomination_value: d.value,
              total_amount: parseFloat(String(saved.total_amount)) || 0,
              value_entered: saved.value_entered != null ? parseFloat(String(saved.value_entered)) : null,
            }
          : { count_type: ct, denomination_type: d.type, denomination_value: d.value, quantity: null, value_entered: null, total_amount: 0 }
      })

    setTakings(rebuild('takings'))
    setFloat(rebuild('float'))

    if (data.card_machines.length) {
      setMachines(MACHINES.map(name => {
        const m = data.card_machines.find(c => c.machine_name === name)
        return m ?? { machine_name: name, total_amount: 0, amex_amount: 0, visa_mc_amount: 0 }
      }))
    }

    setPageState(data.cash_up.status === 'final' ? 'locked' : 'editing')
  }

  // Auto-check on mount and whenever date changes; auto-fetch Newbook in parallel
  useEffect(() => {
    setPageState('checking')
    setCashUp(null)
    setTakings(initDenominations('takings'))
    setFloat(initDenominations('float'))
    setMachines(initMachines())
    setNotes('')
    setAttachments([])
    setNewbookTotals(null)
    setTillPayments([])
    setTransactionBreakdown(null)
    setCheckedItems(new Set())

    api.get<{
      cash_up: CashUp; denominations: Denomination[]; card_machines: CardMachine[];
      reconciliation: ReconciliationRow[]; attachments: Attachment[]
    }>(`/cashup?date=${date}`)
      .then(data => applyLoaded(data))
      .catch(e => {
        if (e instanceof Error && e.message === 'Not found') setPageState('empty')
        else { flash('Failed to load data for this date.', false); setPageState('empty') }
      })

    // Auto-fetch Newbook — soft failure, user can retry with the button
    api.post<{ count: number; totals: PaymentTotals; till_payments: TillPayment[]; transaction_breakdown: TransactionBreakdown }>(
      '/newbook/payments', { date }
    ).then(data => {
      setNewbookTotals(data.totals)
      setTillPayments(data.till_payments || [])
      setTransactionBreakdown(data.transaction_breakdown || null)
    }).catch(() => { /* silently ignore — button still available */ })
  }, [date])

  function updateDenom(list: Denomination[], setList: (d: Denomination[]) => void, idx: number, field: 'quantity' | 'value_entered', raw: string) {
    const val = raw === '' ? null : parseFloat(raw)
    const updated = list.map((d, i) => {
      if (i !== idx) return d
      if (field === 'quantity') {
        const qty = val === null ? null : Math.max(0, Math.round(val))
        return { ...d, quantity: qty, value_entered: null, total_amount: qty === null ? 0 : qty * d.denomination_value }
      } else {
        const ve = val === null ? null : Math.max(0, val)
        return { ...d, value_entered: ve, quantity: null, total_amount: ve ?? 0 }
      }
    })
    setList(updated)
  }

  function updateMachine(idx: number, field: 'total_amount' | 'amex_amount', raw: string) {
    const val = raw === '' ? 0 : parseFloat(raw) || 0
    setMachines(machines.map((m, i) => {
      if (i !== idx) return m
      const total = field === 'total_amount' ? val : m.total_amount
      const amex  = field === 'amex_amount'  ? val : m.amex_amount
      return { ...m, total_amount: total, amex_amount: amex, visa_mc_amount: Math.max(0, total - amex) }
    }))
  }

  async function fetchNewbook() {
    setFetching(true)
    try {
      const data = await api.post<{
        count: number; totals: PaymentTotals; till_payments: TillPayment[]; transaction_breakdown: TransactionBreakdown
      }>('/newbook/payments', { date })
      setNewbookTotals(data.totals)
      setTillPayments(data.till_payments || [])
      setTransactionBreakdown(data.transaction_breakdown || null)
      setCheckedItems(new Set())
      flash(`Fetched ${data.count} payment(s) from Newbook.`)
    } catch (e: unknown) {
      flash(e instanceof Error ? e.message : 'Failed to fetch Newbook data.', false)
    } finally {
      setFetching(false)
    }
  }

  async function save(status: 'draft' | 'final') {
    setSaving(true)
    try {
      const allDenoms = [...takings, ...float].filter(d => d.total_amount > 0)
      const result = await api.post<{ cash_up_id: number; message: string }>('/cashup/save', {
        session_date: date,
        status,
        notes,
        denominations: allDenoms.map(d => ({
          count_type: d.count_type,
          type: d.denomination_type,
          value: d.denomination_value,
          quantity: d.quantity,
          value_entered: d.value_entered,
          total_amount: d.total_amount,
        })),
        card_machines: machines.map(m => ({
          name: m.machine_name,
          total: m.total_amount,
          amex: m.amex_amount,
          visa_mc: m.visa_mc_amount,
        })),
      })
      flash(result.message)
      if (status === 'final') {
        setCashUp(prev => prev ? { ...prev, status: 'final' } : null)
        setPageState('locked')
      }
    } catch (e: unknown) {
      flash(e instanceof Error ? e.message : 'Save failed.', false)
    } finally {
      setSaving(false)
    }
  }

  // Build reconciliation rows from local + Newbook data
  const recon: ReconciliationRow[] = newbookTotals ? [
    { category: 'Cash',            banked_amount: denomTotal(takings), reported_amount: newbookTotals.cash },
    { category: 'PDQ Visa/MC',     banked_amount: machines.reduce((s, m) => s + m.visa_mc_amount, 0), reported_amount: newbookTotals.manual_visa_mc },
    { category: 'PDQ Amex',        banked_amount: machines.reduce((s, m) => s + m.amex_amount, 0),    reported_amount: newbookTotals.manual_amex },
    { category: 'Gateway Visa/MC', banked_amount: newbookTotals.gateway_visa_mc, reported_amount: newbookTotals.gateway_visa_mc },
    { category: 'Gateway Amex',    banked_amount: newbookTotals.gateway_amex,    reported_amount: newbookTotals.gateway_amex },
    { category: 'BACS',            banked_amount: newbookTotals.bacs,            reported_amount: newbookTotals.bacs },
  ] : []

  const totalPdq = machines.reduce((s, m) => s + m.total_amount, 0)

  return (
    <div style={{ padding: '1.5rem', maxWidth: '900px' }}>
      <PageHeader title="Daily Cash Up" />

      {msg && (
        <div style={{
          background: msg.ok ? '#dcfce7' : '#fee2e2', color: msg.ok ? '#16a34a' : 'var(--danger)',
          border: `1px solid ${msg.ok ? '#bbf7d0' : '#fecaca'}`, borderRadius: '6px',
          padding: '0.625rem 1rem', marginBottom: '1rem', fontSize: '0.875rem',
        }}>
          {msg.text}
        </div>
      )}

      {/* Date selector */}
      <Card style={{ marginBottom: '1rem', display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }}>
        <div>
          <label style={{ fontSize: '0.8rem', color: 'var(--text-mid)', display: 'block', marginBottom: '0.25rem' }}>Business Date</label>
          <input type="date" value={date}
            onChange={e => setDate(e.target.value)}
            style={{ border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.45rem 0.75rem', fontSize: '0.9rem' }}
          />
        </div>
        {cashUp && <div style={{ paddingBottom: '1px' }}><StatusBadge status={cashUp.status} /></div>}
      </Card>

      {/* Checking */}
      {pageState === 'checking' && (
        <div style={{ color: 'var(--text-mid)', padding: '2rem 0', textAlign: 'center' }}>Loading…</div>
      )}

      {/* No cash up for this date */}
      {pageState === 'empty' && (
        <Card style={{ textAlign: 'center', padding: '2.5rem 1.5rem' }}>
          <p style={{ color: 'var(--text-mid)', marginBottom: '1.25rem' }}>No cash up recorded for this date.</p>
          <Btn onClick={() => setPageState('editing')}>Start Cash Up</Btn>
        </Card>
      )}

      {/* Locked banner */}
      {pageState === 'locked' && (
        <div style={{
          background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: '6px',
          padding: '0.75rem 1rem', marginBottom: '1rem', fontSize: '0.875rem',
          color: '#16a34a', display: 'flex', alignItems: 'center', gap: '0.5rem',
        }}>
          <CheckCircle size={15} /> This cash up has been finalised and is locked.
        </div>
      )}

      {(pageState === 'editing' || pageState === 'locked') && <>

      {/* Cash denomination — Takings */}
      <Card style={{ marginBottom: '1rem' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem' }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700 }}>Cash Takings</h2>
          <span style={{ fontWeight: 700, fontSize: '1.1rem' }}>{fmtGBP(denomTotal(takings))}</span>
        </div>
        <DenomGrid denoms={takings} onChange={(i, f, v) => updateDenom(takings, setTakings, i, f, v)} disabled={isFinal} tabBase={0} />
      </Card>

      {/* Float (collapsible) */}
      <Card style={{ marginBottom: '1rem' }}>
        <button onClick={() => setShowFloat(f => !f)} style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          width: '100%', background: 'none', border: 'none', padding: 0, cursor: 'pointer',
        }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700 }}>Float Count</h2>
          <span style={{ fontSize: '0.9rem', color: 'var(--text-mid)' }}>
            {fmtGBP(denomTotal(float))} {showFloat ? '▲' : '▼'}
          </span>
        </button>
        {showFloat && (
          <div style={{ marginTop: '1rem' }}>
            <DenomGrid denoms={float} onChange={(i, f, v) => updateDenom(float, setFloat, i, f, v)} disabled={isFinal} tabBase={24} />
          </div>
        )}
      </Card>

      {/* Card Machines */}
      <Card style={{ marginBottom: '1rem' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem' }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700 }}>Card Machines (PDQ)</h2>
          <span style={{ fontWeight: 700, fontSize: '1.1rem' }}>Total: {fmtGBP(totalPdq)}</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
          {machines.map((m, i) => (
            <div key={m.machine_name} style={{ border: '1px solid var(--card-border)', borderRadius: '8px', padding: '1rem' }}>
              <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '0.75rem', color: 'var(--text-mid)' }}>
                {m.machine_name}
              </h3>
              <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
                <MoneyInput label="Total" value={m.total_amount}
                  onChange={v => updateMachine(i, 'total_amount', v)} disabled={isFinal} />
                <MoneyInput label="Amex" value={m.amex_amount}
                  onChange={v => updateMachine(i, 'amex_amount', v)} disabled={isFinal} />
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '0.875rem', paddingTop: '0.25rem' }}>
                  <span style={{ color: 'var(--text-mid)' }}>Visa / MC</span>
                  <span style={{ fontWeight: 600 }}>{fmtGBP(m.visa_mc_amount)}</span>
                </div>
              </div>
            </div>
          ))}
        </div>
      </Card>

      {/* PDQ Z-Reports — one upload area per machine */}
      {cashUp && (
        <Card style={{ marginBottom: '1rem' }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700, marginBottom: '0.75rem' }}>PDQ Z-Reports</h2>
          <p style={{ fontSize: '0.75rem', color: 'var(--text-mid)', marginBottom: '1rem' }}>
            Upload the end-of-day Z-report printout for each card machine.
          </p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>
            {MACHINES.map(name => (
              <div key={name}>
                <div style={{ fontSize: '0.8rem', fontWeight: 600, marginBottom: '0.5rem' }}>{name}</div>
                <PhotoUploader
                  cashUpId={cashUp.id}
                  attachmentType="pdq_z_report"
                  label={name}
                  attachments={attachments}
                  onAdded={a => setAttachments(prev => [...prev, a])}
                  onRemoved={id => setAttachments(prev => prev.filter(a => a.id !== id))}
                  disabled={isFinal}
                />
              </div>
            ))}
          </div>
        </Card>
      )}

      {/* Newbook + Reconciliation */}
      <Card style={{ marginBottom: '1rem' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem' }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700 }}>Newbook Reconciliation</h2>
          <Btn onClick={fetchNewbook} disabled={fetching || isFinal} small>
            {fetching ? <><Loader size={13} style={{ animation: 'spin 1s linear infinite' }} /> Fetching…</> : <><RefreshCw size={13} /> Fetch Payments</>}
          </Btn>
        </div>

        {newbookTotals && (
          <>
            <table style={{ width: '100%', fontSize: '0.875rem', borderCollapse: 'collapse' }}>
              <thead>
                <tr style={{ borderBottom: '2px solid var(--card-border)' }}>
                  {['Category', 'Banked', 'Reported', 'Variance'].map(h => (
                    <th key={h} style={{ padding: '0.4rem 0.5rem', textAlign: h === 'Category' ? 'left' : 'right', color: 'var(--text-mid)', fontWeight: 600 }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {recon.map(row => {
                  const variance = row.banked_amount - row.reported_amount
                  const varColor = Math.abs(variance) < 0.01 ? 'var(--text-mid)' : variance > 0 ? 'var(--success)' : 'var(--danger)'
                  return (
                    <tr key={row.category} style={{ borderBottom: '1px solid var(--card-border)' }}>
                      <td style={{ padding: '0.5rem' }}>{row.category}</td>
                      <td style={{ padding: '0.5rem', textAlign: 'right' }}>{fmtGBP(row.banked_amount)}</td>
                      <td style={{ padding: '0.5rem', textAlign: 'right' }}>{fmtGBP(row.reported_amount)}</td>
                      <td style={{ padding: '0.5rem', textAlign: 'right', color: varColor, fontWeight: 600 }}>
                        {Math.abs(variance) < 0.01 ? '—' : (variance > 0 ? '+' : '') + fmtGBP(Math.abs(variance))}
                      </td>
                    </tr>
                  )
                })}
              </tbody>
            </table>

            {tillPayments.length > 0 && (
              <div style={{ marginTop: '1rem' }}>
                <h3 style={{ fontSize: '0.875rem', fontWeight: 600, marginBottom: '0.5rem', color: 'var(--text-mid)' }}>
                  Till / Restaurant Transactions
                </h3>
                <table style={{ width: '100%', fontSize: '0.8rem', borderCollapse: 'collapse' }}>
                  <thead>
                    <tr style={{ borderBottom: '1px solid var(--card-border)' }}>
                      <th style={{ padding: '0.35rem 0.5rem', textAlign: 'left', color: 'var(--text-mid)' }}>Type</th>
                      <th style={{ padding: '0.35rem 0.5rem', textAlign: 'right', color: 'var(--text-mid)' }}>Qty</th>
                      <th style={{ padding: '0.35rem 0.5rem', textAlign: 'right', color: 'var(--text-mid)' }}>Total</th>
                    </tr>
                  </thead>
                  <tbody>
                    {tillPayments.map(t => (
                      <tr key={t.payment_type} style={{ borderBottom: '1px solid var(--card-border)' }}>
                        <td style={{ padding: '0.35rem 0.5rem' }}>{t.payment_type}</td>
                        <td style={{ padding: '0.35rem 0.5rem', textAlign: 'right' }}>{t.quantity}</td>
                        <td style={{ padding: '0.35rem 0.5rem', textAlign: 'right' }}>{fmtGBP(t.total_value)}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          {transactionBreakdown && (
            <TransactionChecklist
              breakdown={transactionBreakdown}
              checked={checkedItems}
              onToggle={key => setCheckedItems(prev => {
                const next = new Set(prev)
                next.has(key) ? next.delete(key) : next.add(key)
                return next
              })}
            />
          )}
          </>
        )}
      </Card>

      {/* Receipt / discrepancy evidence */}
      {cashUp && (
        <Card style={{ marginBottom: '1rem' }}>
          <h2 style={{ fontSize: '1rem', fontWeight: 700, marginBottom: '0.5rem' }}>Receipt Evidence &amp; Error Photos</h2>
          <p style={{ fontSize: '0.75rem', color: 'var(--text-mid)', marginBottom: '0.75rem' }}>
            Upload photos of receipts with errors, discrepancies or anything needing a record.
          </p>
          <PhotoUploader
            cashUpId={cashUp.id}
            attachmentType="receipt_error"
            label={null}
            attachments={attachments}
            onAdded={a => setAttachments(prev => [...prev, a])}
            onRemoved={id => setAttachments(prev => prev.filter(a => a.id !== id))}
            disabled={false}
          />
        </Card>
      )}

      {/* Notes */}
      <Card style={{ marginBottom: '1rem' }}>
        <label style={{ fontSize: '0.875rem', fontWeight: 600, display: 'block', marginBottom: '0.5rem' }}>Notes</label>
        <textarea
          value={notes} onChange={e => setNotes(e.target.value)}
          disabled={isFinal}
          rows={3}
          placeholder="Explain any variances or issues…"
          style={{
            width: '100%', border: '1px solid var(--card-border)', borderRadius: '6px',
            padding: '0.6rem 0.75rem', fontSize: '0.875rem', resize: 'vertical',
            background: isFinal ? 'var(--body-bg)' : 'white',
          }}
        />
      </Card>

      {/* Action buttons */}
      {pageState === 'editing' && (
        <div style={{ display: 'flex', gap: '0.75rem', alignItems: 'center' }}>
          <Btn onClick={() => save('draft')} disabled={saving} variant="secondary">
            <Save size={14} style={{ marginRight: '0.4rem' }} />
            {saving ? 'Saving…' : 'Save Draft'}
          </Btn>
          {canFinalise ? (
            <Btn onClick={() => save('final')} disabled={saving}>
              <CheckCircle size={14} style={{ marginRight: '0.4rem' }} />
              {saving ? 'Submitting…' : 'Submit Final'}
            </Btn>
          ) : (
            <span style={{ fontSize: '0.8rem', color: 'var(--text-mid)' }}>
              Save as draft — a manager with finalise permission will submit it.
            </span>
          )}
        </div>
      )}

      </> /* end editing | locked */}

      <style>{`@keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }`}</style>
    </div>
  )
}

function DenomGrid({ denoms, onChange, disabled, tabBase = 0 }: {
  denoms: Denomination[]
  onChange: (idx: number, field: 'quantity' | 'value_entered', val: string) => void
  disabled: boolean
  tabBase?: number
}) {
  const n = denoms.length
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: '80px 1fr 1fr 80px', gap: '0.25rem 0.5rem', marginBottom: '0.35rem' }}>
        {['Denom', 'Qty', 'Value Override', 'Total'].map(h => (
          <span key={h} style={{ fontSize: '0.75rem', color: 'var(--text-mid)', fontWeight: 600 }}>{h}</span>
        ))}
      </div>
      {GBP_DENOMINATIONS.map((d, i) => {
        const row = denoms[i]
        return (
          <div key={d.value} style={{ display: 'grid', gridTemplateColumns: '80px 1fr 1fr 80px', gap: '0.25rem 0.5rem', marginBottom: '0.2rem', alignItems: 'center' }}>
            <span style={{ fontSize: '0.875rem', fontWeight: 600 }}>{d.label}</span>
            <input
              type="number" min="0" step="1"
              value={row.quantity ?? ''}
              onChange={e => onChange(i, 'quantity', e.target.value)}
              disabled={disabled}
              placeholder="0"
              tabIndex={tabBase + i + 1}
              style={inputSt}
            />
            <input
              type="number" min="0" step="0.01"
              value={row.value_entered ?? ''}
              onChange={e => onChange(i, 'value_entered', e.target.value)}
              disabled={disabled || row.quantity !== null}
              placeholder="—"
              tabIndex={tabBase + n + i + 1}
              style={{ ...inputSt, opacity: row.quantity !== null ? 0.4 : 1 }}
            />
            <span style={{ fontSize: '0.875rem', textAlign: 'right' }}>
              {row.total_amount > 0 ? fmtGBP(row.total_amount) : '—'}
            </span>
          </div>
        )
      })}
    </div>
  )
}

function PhotoUploader({
  cashUpId, attachmentType, label, attachments, onAdded, onRemoved, disabled,
}: {
  cashUpId: number
  attachmentType: 'pdq_z_report' | 'receipt_error' | 'other'
  label: string | null
  attachments: Attachment[]
  onAdded: (a: Attachment) => void
  onRemoved: (id: number) => void
  disabled: boolean
}) {
  const [uploading, setUploading] = useState(false)
  const inputRef = useRef<HTMLInputElement>(null)

  const mine = attachments.filter(a =>
    a.attachment_type === attachmentType &&
    (label === null ? !a.label : a.label === label)
  )

  async function handleFiles(files: FileList) {
    setUploading(true)
    for (const file of Array.from(files)) {
      try {
        const a = await uploadAttachment(cashUpId, file, attachmentType, label ?? undefined)
        onAdded(a as Attachment)
      } catch (e) {
        console.error('Upload failed', e)
      }
    }
    setUploading(false)
    if (inputRef.current) inputRef.current.value = ''
  }

  async function remove(id: number) {
    await api.delete(`/attachments/${id}`)
    onRemoved(id)
  }

  return (
    <div style={{ display: 'flex', gap: '0.625rem', flexWrap: 'wrap', alignItems: 'flex-start' }}>
      {mine.map(a => (
        <div key={a.id} style={{ position: 'relative', width: '88px', height: '88px', flexShrink: 0 }}>
          {a.mime_type.startsWith('image/') ? (
            <a href={`/cashup/api/uploads${a.file_path}`} target="_blank" rel="noopener noreferrer">
              <img src={`/cashup/api/uploads${a.file_path}`} alt={a.file_name}
                style={{ width: '88px', height: '88px', objectFit: 'cover', borderRadius: '6px', border: '1px solid var(--card-border)', display: 'block' }} />
            </a>
          ) : (
            <a href={`/cashup/api/uploads${a.file_path}`} target="_blank" rel="noopener noreferrer"
              style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', width: '88px', height: '88px', border: '1px solid var(--card-border)', borderRadius: '6px', background: 'var(--body-bg)', textDecoration: 'none', color: 'var(--text-mid)', gap: '4px' }}>
              <FileText size={24} />
              <span style={{ fontSize: '0.6rem', textAlign: 'center', padding: '0 4px', wordBreak: 'break-all' }}>
                {a.file_name.slice(0, 14)}
              </span>
            </a>
          )}
          {!disabled && (
            <button onClick={() => remove(a.id)}
              style={{ position: 'absolute', top: '-8px', right: '-8px', width: '20px', height: '20px', borderRadius: '50%', background: '#dc2626', color: '#fff', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1 }}>
              <X size={10} />
            </button>
          )}
        </div>
      ))}
      {!disabled && (
        <button onClick={() => inputRef.current?.click()}
          style={{ width: '88px', height: '88px', border: '2px dashed var(--card-border)', borderRadius: '6px', background: 'var(--body-bg)', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '4px', color: 'var(--text-mid)', fontSize: '0.7rem' }}>
          {uploading ? <Loader size={18} style={{ animation: 'spin 1s linear infinite' }} /> : <><Camera size={18} /><span>Add photo</span></>}
        </button>
      )}
      <input ref={inputRef} type="file" accept="image/*,application/pdf" multiple hidden
        onChange={e => e.target.files?.length && handleFiles(e.target.files)} />
    </div>
  )
}

const inputSt: React.CSSProperties = {
  border: '1px solid var(--card-border)', borderRadius: '4px',
  padding: '0.3rem 0.5rem', fontSize: '0.875rem', width: '100%',
  background: 'white',
}

const SECTION_LABELS: Record<keyof TransactionBreakdown, string> = {
  reception_manual:  'Reception — Manual',
  reception_gateway: 'Reception — Gateway',
  restaurant_bar:    'Restaurant / Bar',
}

function TransactionChecklist({ breakdown, checked, onToggle }: {
  breakdown: TransactionBreakdown
  checked: Set<string>
  onToggle: (key: string) => void
}) {
  const [openSections, setOpenSections] = useState<Set<string>>(new Set())

  const allItems: Array<{ key: string; section: string; category: string; item: TransactionItem }> = []
  for (const [section, categories] of Object.entries(breakdown) as [keyof TransactionBreakdown, Record<string, TransactionItem[]>][]) {
    for (const [category, items] of Object.entries(categories)) {
      items.forEach((item, i) => allItems.push({ key: `${section}:${category}:${i}`, section, category, item }))
    }
  }

  const totalItems = allItems.length
  const checkedCount = allItems.filter(a => checked.has(a.key)).length

  if (totalItems === 0) return null

  const toggleSection = (s: string) => setOpenSections(prev => {
    const next = new Set(prev); next.has(s) ? next.delete(s) : next.add(s); return next
  })

  return (
    <div style={{ marginTop: '1.25rem', borderTop: '1px solid var(--card-border)', paddingTop: '1rem' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
        <h3 style={{ fontSize: '0.875rem', fontWeight: 700 }}>Transaction Breakdown</h3>
        <span style={{ fontSize: '0.75rem', color: checkedCount === totalItems ? 'var(--success)' : 'var(--text-mid)' }}>
          {checkedCount}/{totalItems} checked
        </span>
      </div>

      {(Object.entries(breakdown) as [keyof TransactionBreakdown, Record<string, TransactionItem[]>][]).map(([section, categories]) => {
        const sectionItems = Object.values(categories).flat()
        if (sectionItems.length === 0) return null
        const sectionKeys = Object.entries(categories).flatMap(([cat, items]) =>
          items.map((_, i) => `${section}:${cat}:${i}`)
        )
        const sectionChecked = sectionKeys.filter(k => checked.has(k)).length
        const isOpen = openSections.has(section)

        return (
          <div key={section} style={{ marginBottom: '0.5rem', border: '1px solid var(--card-border)', borderRadius: '6px', overflow: 'hidden' }}>
            <button onClick={() => toggleSection(section)} style={{
              display: 'flex', justifyContent: 'space-between', alignItems: 'center',
              width: '100%', padding: '0.5rem 0.75rem', background: 'var(--body-bg)',
              border: 'none', cursor: 'pointer', fontSize: '0.8rem', fontWeight: 600,
            }}>
              <span>{SECTION_LABELS[section]}</span>
              <span style={{ color: sectionChecked === sectionKeys.length ? 'var(--success)' : 'var(--text-mid)', fontSize: '0.75rem' }}>
                {sectionChecked}/{sectionKeys.length} {isOpen ? '▲' : '▼'}
              </span>
            </button>

            {isOpen && (
              <div style={{ padding: '0.25rem 0' }}>
                {Object.entries(categories).map(([category, items]) => (
                  <div key={category}>
                    <div style={{ padding: '0.25rem 0.75rem', fontSize: '0.7rem', fontWeight: 700, color: 'var(--text-mid)', textTransform: 'uppercase', letterSpacing: '0.05em', background: 'var(--card-bg)' }}>
                      {category}
                    </div>
                    {items.map((item, i) => {
                      const key = `${section}:${category}:${i}`
                      const isDone = checked.has(key)
                      return (
                        <div key={key} onClick={() => onToggle(key)} style={{
                          display: 'grid', gridTemplateColumns: '20px 1fr auto auto',
                          gap: '0.5rem', alignItems: 'center',
                          padding: '0.35rem 0.75rem', cursor: 'pointer',
                          background: isDone ? '#f0fdf4' : 'white',
                          borderBottom: '1px solid var(--card-border)',
                          opacity: isDone ? 0.6 : 1,
                        }}>
                          <span style={{ fontSize: '0.9rem', color: isDone ? 'var(--success)' : 'var(--text-mid)' }}>
                            {isDone ? '✓' : '○'}
                          </span>
                          <div>
                            <span style={{ fontSize: '0.8rem', textDecoration: isDone ? 'line-through' : 'none' }}>
                              {item.details || item.payment_type}
                            </span>
                            {item.time && (
                              <span style={{ fontSize: '0.7rem', color: 'var(--text-mid)', marginLeft: '0.5rem' }}>{item.time.slice(11, 16)}</span>
                            )}
                          </div>
                          <span style={{ fontSize: '0.7rem', color: 'var(--text-mid)' }}>{item.payment_type}</span>
                          <span style={{ fontSize: '0.8rem', fontWeight: 600, color: item.is_voided ? 'var(--danger)' : undefined }}>
                            {item.is_voided ? '-' : ''}{fmtGBP(Math.abs(item.amount))}
                          </span>
                        </div>
                      )
                    })}
                  </div>
                ))}
              </div>
            )}
          </div>
        )
      })}
    </div>
  )
}

function MoneyInput({ label, value, onChange, disabled }: {
  label: string; value: number; onChange: (v: string) => void; disabled: boolean
}) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '0.5rem' }}>
      <label style={{ fontSize: '0.8rem', color: 'var(--text-mid)', minWidth: '60px' }}>{label}</label>
      <input
        type="number" min="0" step="0.01"
        value={value || ''}
        onChange={e => onChange(e.target.value)}
        disabled={disabled}
        placeholder="0.00"
        style={{ ...inputSt, width: '110px', textAlign: 'right' }}
      />
    </div>
  )
}
