import { useState, useEffect } from 'react'
import { RefreshCw, Save, CheckCircle, Loader } from 'lucide-react'
import { api } from '../api'
import { PageHeader, Card, Btn, StatusBadge } from '../components/Layout'
import {
  GBP_DENOMINATIONS, fmtGBP, today,
  type User, type CashUp, type Denomination, type CardMachine,
  type PaymentTotals, type ReconciliationRow, type TillPayment, type Attachment,
} 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: _user }: Props) {
  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 [, setAttachments] = useState<Attachment[]>([])
  const [newbookTotals, setNewbookTotals] = useState<PaymentTotals | null>(null)
  const [tillPayments, setTillPayments] = useState<TillPayment[]>([])
  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
  useEffect(() => {
    setPageState('checking')
    setCashUp(null)
    setTakings(initDenominations('takings'))
    setFloat(initDenominations('float'))
    setMachines(initMachines())
    setNotes('')
    setAttachments([])
    setNewbookTotals(null)
    setTillPayments([])

    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') }
      })
  }, [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[]
      }>('/newbook/payments', { date })
      setNewbookTotals(data.totals)
      setTillPayments(data.till_payments || [])
      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>

      {/* 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>
            )}
          </>
        )}
      </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' }}>
          <Btn onClick={() => save('draft')} disabled={saving} variant="secondary">
            <Save size={14} style={{ marginRight: '0.4rem' }} />
            {saving ? 'Saving…' : 'Save Draft'}
          </Btn>
          <Btn onClick={() => save('final')} disabled={saving}>
            <CheckCircle size={14} style={{ marginRight: '0.4rem' }} />
            {saving ? 'Submitting…' : 'Submit Final'}
          </Btn>
        </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>
  )
}

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

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>
  )
}
