'use client';

import { useEffect, useMemo, useState } from 'react';
import { Gift, Loader2, Plus, X, RefreshCw, Download, Trash2, Search, AlertCircle, Mail, Copy, Check } from 'lucide-react';
import { toast } from 'sonner';
import { usePageHeader } from '@client/contexts/PageHeaderContext';
import FeatureGuard from '@client/components/FeatureGuard';
import PermissionDenied from '@client/components/ui/PermissionDenied';

interface Settings {
  enabled: boolean;
  denominations: number[];
  custom_amount_enabled: boolean;
  custom_min: number;
  custom_max: number;
  currency: string;
  default_expiry_months: number | null;
  code_length: number;
  code_prefix: string;
  brand_logo_url: string | null;
  brand_primary_color: string;
  message_template: string;
  email_from_line: string | null;
  redemption_rule: 'subtotal' | 'total';
  stack_with_coupons: boolean;
  stack_with_loyalty: boolean;
  show_full_code_on_voucher: boolean;
}

interface CardListItem {
  id: string;
  masked_code: string;
  original_amount: number;
  balance: number;
  currency: string;
  recipient_name: string;
  recipient_email: string | null;
  sender_name: string | null;
  status: string;
  expires_at: string | null;
  created_at: string;
}

interface Stats {
  total: number;
  active: number;
  redeemed: number;
  expired: number;
  void: number;
  total_issued: number;
  outstanding: number;
}

export default function GiftCardsPage() {
  usePageHeader('Gift Cards', 'Issue, redeem, and brand restaurant-wide gift cards');
  return (
    <FeatureGuard feature="gift_cards" featureName="Gift Cards">
      <GiftCardsAdmin />
    </FeatureGuard>
  );
}

function GiftCardsAdmin() {
  const [tab, setTab] = useState<'cards' | 'settings'>('cards');
  // Settings is fetched ONCE at the top of the page and passed down. Both
  // IssueDialog (under CardsTab) and SettingsTab used to mount their own
  // useEffect that hit /api/gift-cards/settings — duplicate work + stale
  // state if you saved settings then opened Issue without remounting.
  const [settings, setSettings] = useState<Settings | null>(null);
  const [forbidden, setForbidden] = useState(false);
  useEffect(() => {
    let cancelled = false;
    fetch('/api/gift-cards/settings').then(r => {
      if (r.status === 403) { if (!cancelled) setForbidden(true); return null; }
      return r.json();
    }).then(j => {
      if (!cancelled && j) setSettings(j.settings);
    }).catch(() => { /* ignore — children show a loader */ });
    return () => { cancelled = true; };
  }, []);

  if (forbidden) {
    return <PermissionDenied sectionName="the Gift Cards section" />;
  }

  return (
    <div className="p-6 max-w-6xl mx-auto">
      <div className="flex gap-2 border-b border-slate-200 mb-6">
        <TabButton label="Cards" active={tab === 'cards'} onClick={() => setTab('cards')} />
        <TabButton label="Settings" active={tab === 'settings'} onClick={() => setTab('settings')} />
      </div>
      {tab === 'cards'
        ? <CardsTab settings={settings} />
        : <SettingsTab settings={settings} setSettings={setSettings} />}
    </div>
  );
}

function TabButton({ label, active, onClick }: { label: string; active: boolean; onClick: () => void }) {
  return (
    <button
      onClick={onClick}
      className={`px-4 py-2 text-sm font-semibold border-b-2 -mb-px ${
        active ? 'border-orange-500 text-orange-600' : 'border-transparent text-slate-500 hover:text-slate-700'
      }`}
    >
      {label}
    </button>
  );
}

function fmtMoney(n: number, currency: string): string {
  try {
    return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(n);
  } catch {
    return `${currency} ${n.toFixed(2)}`;
  }
}

// ---------- Cards tab ----------

function CardsTab({ settings }: { settings: Settings | null }) {
  const [items, setItems] = useState<CardListItem[]>([]);
  const [stats, setStats] = useState<Stats | null>(null);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [statusFilter, setStatusFilter] = useState<string>('');
  const [dateFrom, setDateFrom] = useState<string>('');
  const [dateTo, setDateTo] = useState<string>('');
  const [page, setPage] = useState(1);
  const [pages, setPages] = useState(1);
  const [issueOpen, setIssueOpen] = useState(false);
  const [newCard, setNewCard] = useState<{ code: string; masked_code: string; amount: number; currency: string } | null>(null);
  const [detailId, setDetailId] = useState<string | null>(null);

  const load = useMemo(() => async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (search) params.set('search', search);
      if (statusFilter) params.set('status', statusFilter);
      if (dateFrom) params.set('date_from', dateFrom);
      if (dateTo) params.set('date_to', dateTo);
      params.set('page', String(page));
      const [listRes, statsRes] = await Promise.all([
        fetch(`/api/gift-cards?${params}`),
        fetch('/api/gift-cards/stats'),
      ]);
      const listJson = await listRes.json();
      const statsJson = await statsRes.json();
      if (listRes.ok) {
        setItems(listJson.items || []);
        setPages(listJson.pages || 1);
      }
      if (statsRes.ok) setStats(statsJson.stats);
    } finally {
      setLoading(false);
    }
  }, [search, statusFilter, dateFrom, dateTo, page]);

  useEffect(() => { void load(); }, [load]);

  const refundCard = async (id: string) => {
    const amountStr = window.prompt('Refund amount?');
    if (!amountStr) return;
    const amount = Number(amountStr);
    if (!Number.isFinite(amount) || amount <= 0) { toast.error('Invalid amount'); return; }
    const res = await fetch(`/api/gift-cards/${id}/refund`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount }),
    });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Refund failed');
      return;
    }
    toast.success('Refund posted');
    await load();
  };
  const voidCard = async (id: string) => {
    if (!window.confirm('Void this card? Its remaining balance becomes 0.')) return;
    const res = await fetch(`/api/gift-cards/${id}/void`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: 'Voided by admin' }) });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Void failed');
      return;
    }
    toast.success('Card voided');
    await load();
  };
  const resendEmail = async (id: string) => {
    const res = await fetch(`/api/gift-cards/${id}/resend`, { method: 'POST' });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Resend failed');
      return;
    }
    toast.success('Email queued');
  };

  return (
    <div>
      {stats && (
        <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-6">
          <StatCard label="Active" value={String(stats.active)} />
          <StatCard label="Redeemed" value={String(stats.redeemed)} />
          <StatCard label="Total issued" value={fmtMoney(stats.total_issued, 'USD')} />
          <StatCard label="Outstanding" value={fmtMoney(stats.outstanding, 'USD')} highlight />
        </div>
      )}

      <div className="flex flex-col sm:flex-row gap-2 mb-4">
        <div className="relative flex-1">
          <Search size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-slate-400" />
          <input
            className="w-full pl-8 pr-3 py-2 text-sm rounded-lg border border-slate-200"
            placeholder="Search by name, email, code…"
            value={search}
            onChange={(e) => { setSearch(e.target.value); setPage(1); }}
          />
        </div>
        <select
          value={statusFilter}
          onChange={(e) => { setStatusFilter(e.target.value); setPage(1); }}
          className="rounded-lg border border-slate-200 text-sm px-2 py-2"
        >
          <option value="">All statuses</option>
          <option value="active">Active</option>
          <option value="redeemed">Redeemed</option>
          <option value="expired">Expired</option>
          <option value="void">Void</option>
        </select>
        <input
          type="date"
          value={dateFrom}
          onChange={(e) => { setDateFrom(e.target.value); setPage(1); }}
          className="rounded-lg border border-slate-200 text-sm px-2 py-2"
          aria-label="Issued from"
          title="Issued from"
        />
        <input
          type="date"
          value={dateTo}
          onChange={(e) => { setDateTo(e.target.value); setPage(1); }}
          className="rounded-lg border border-slate-200 text-sm px-2 py-2"
          aria-label="Issued to"
          title="Issued to"
        />
        {(dateFrom || dateTo) && (
          <button
            onClick={() => { setDateFrom(''); setDateTo(''); setPage(1); }}
            className="rounded-lg border border-slate-200 text-sm px-2 py-2 text-slate-500 hover:bg-slate-50"
            title="Clear date filter"
          >
            Clear dates
          </button>
        )}
        <button onClick={() => setIssueOpen(true)} className="bg-orange-500 hover:bg-orange-600 text-white rounded-lg px-3 py-2 text-sm font-semibold flex items-center gap-1">
          <Plus size={14} /> Issue card
        </button>
      </div>

      {loading ? (
        <div className="py-16 flex justify-center text-slate-500"><Loader2 className="animate-spin mr-2" /> Loading…</div>
      ) : items.length === 0 ? (
        <div className="py-16 text-center text-slate-500 border border-dashed border-slate-200 rounded-xl">
          <Gift size={28} className="mx-auto mb-2 opacity-50" />
          No gift cards yet — issue one above.
        </div>
      ) : (
        <div className="overflow-hidden rounded-xl border border-slate-200">
          <table className="w-full text-sm">
            <thead className="bg-slate-50 text-xs text-slate-500 uppercase">
              <tr>
                <th className="text-left px-3 py-2">Code</th>
                <th className="text-left px-3 py-2">Recipient</th>
                <th className="text-right px-3 py-2">Original</th>
                <th className="text-right px-3 py-2">Balance</th>
                <th className="text-left px-3 py-2">Status</th>
                <th className="text-left px-3 py-2">Created</th>
                <th className="px-3 py-2"></th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-100">
              {items.map((c) => (
                <tr key={c.id} className="hover:bg-slate-50 cursor-pointer" onClick={() => setDetailId(c.id)}>
                  <td className="px-3 py-2 font-mono text-xs">{c.masked_code}</td>
                  <td className="px-3 py-2">
                    <div className="font-medium text-slate-900">{c.recipient_name}</div>
                    {c.recipient_email && <div className="text-xs text-slate-500">{c.recipient_email}</div>}
                  </td>
                  <td className="px-3 py-2 text-right">{fmtMoney(c.original_amount, c.currency)}</td>
                  <td className="px-3 py-2 text-right font-semibold">{fmtMoney(c.balance, c.currency)}</td>
                  <td className="px-3 py-2"><StatusPill status={c.status} /></td>
                  <td className="px-3 py-2 text-xs text-slate-500">{new Date(c.created_at).toLocaleDateString()}</td>
                  <td className="px-3 py-2" onClick={(e) => e.stopPropagation()}>
                    <div className="flex gap-1 justify-end">
                      <a href={`/api/gift-cards/${c.id}/voucher`} target="_blank" rel="noopener noreferrer" title="Download voucher" className="p-1.5 rounded hover:bg-slate-100">
                        <Download size={14} />
                      </a>
                      {c.recipient_email && (
                        <button onClick={() => resendEmail(c.id)} title="Resend email" className="p-1.5 rounded hover:bg-slate-100"><Mail size={14} /></button>
                      )}
                      <button onClick={() => refundCard(c.id)} title="Refund" className="p-1.5 rounded hover:bg-slate-100"><RefreshCw size={14} /></button>
                      {c.status !== 'void' && (
                        <button onClick={() => voidCard(c.id)} title="Void" className="p-1.5 rounded hover:bg-red-50 text-red-600"><Trash2 size={14} /></button>
                      )}
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {pages > 1 && (
        <div className="flex justify-center items-center gap-2 mt-4 text-sm">
          <button disabled={page <= 1} onClick={() => setPage((p) => Math.max(1, p - 1))} className="px-3 py-1 rounded border border-slate-200 disabled:opacity-40">Prev</button>
          <span className="text-slate-500">Page {page} of {pages}</span>
          <button disabled={page >= pages} onClick={() => setPage((p) => Math.min(pages, p + 1))} className="px-3 py-1 rounded border border-slate-200 disabled:opacity-40">Next</button>
        </div>
      )}

      {issueOpen && <IssueDialog settings={settings} onClose={() => setIssueOpen(false)} onIssued={async (card) => {
        setNewCard({ code: card.code, masked_code: card.masked_code, amount: card.original_amount, currency: card.currency });
        setIssueOpen(false);
        await load();
      }} />}
      {newCard && <CodeRevealDialog card={newCard} onClose={() => setNewCard(null)} />}
      {detailId && <CardDetailDrawer cardId={detailId} onClose={() => setDetailId(null)} onChanged={load} />}
    </div>
  );
}

interface LedgerEntry {
  id: string;
  entry_type: string;
  amount: number;
  balance_after: number;
  note: string | null;
  order_id: string | null;
  created_at: string;
}

function CardDetailDrawer({ cardId, onClose, onChanged }: { cardId: string; onClose: () => void; onChanged: () => Promise<void> | void }) {
  const [card, setCard] = useState<CardListItem & { personal_message?: string | null; expires_at: string | null; code_last4?: string } | null>(null);
  const [ledger, setLedger] = useState<LedgerEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [copied, setCopied] = useState(false);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      setLoading(true);
      try {
        const res = await fetch(`/api/gift-cards/${cardId}`);
        const json = await res.json();
        if (!cancelled && res.ok) {
          setCard(json.card);
          setLedger(json.ledger || []);
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [cardId]);

  // Copy the masked code (with last4) — useful for matching against a
  // customer-provided receipt or order. The full cleartext code is
  // intentionally never stored on the server, so it cannot be revealed
  // here after issuance.
  const copy = async () => {
    if (!card) return;
    try {
      await navigator.clipboard.writeText(card.masked_code);
      setCopied(true);
      toast.success('Masked code copied');
      setTimeout(() => setCopied(false), 1500);
    } catch {
      toast.error('Could not copy');
    }
  };

  const last4 = card?.masked_code?.slice(-4) ?? '';
  const copyLast4 = async () => {
    if (!last4) return;
    try {
      await navigator.clipboard.writeText(last4);
      toast.success(`Copied last 4 (${last4})`);
    } catch {
      toast.error('Could not copy');
    }
  };

  const refundCard = async () => {
    if (!card) return;
    const amountStr = window.prompt('Refund amount?');
    if (!amountStr) return;
    const amount = Number(amountStr);
    if (!Number.isFinite(amount) || amount <= 0) { toast.error('Invalid amount'); return; }
    const res = await fetch(`/api/gift-cards/${card.id}/refund`, {
      method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount }),
    });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Refund failed'); return;
    }
    toast.success('Refund posted');
    const r = await fetch(`/api/gift-cards/${cardId}`).then(r => r.json());
    setCard(r.card); setLedger(r.ledger || []);
    await onChanged();
  };
  const voidCard = async () => {
    if (!card) return;
    if (!window.confirm('Void this card? Its remaining balance becomes 0.')) return;
    const res = await fetch(`/api/gift-cards/${card.id}/void`, {
      method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: 'Voided by admin' }),
    });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Void failed'); return;
    }
    toast.success('Card voided');
    const r = await fetch(`/api/gift-cards/${cardId}`).then(r => r.json());
    setCard(r.card); setLedger(r.ledger || []);
    await onChanged();
  };
  const resendEmail = async () => {
    if (!card) return;
    const res = await fetch(`/api/gift-cards/${card.id}/resend`, { method: 'POST' });
    if (!res.ok) {
      const json = await res.json().catch(() => ({}));
      toast.error(json?.error || 'Resend failed'); return;
    }
    toast.success('Email queued');
  };

  return (
    <div className="fixed inset-0 z-50 bg-black/40" onClick={onClose}>
      <div className="absolute right-0 top-0 bottom-0 w-full max-w-md bg-white shadow-xl overflow-y-auto" onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center justify-between px-5 py-4 border-b border-slate-200 sticky top-0 bg-white z-10">
          <h3 className="text-lg font-bold text-slate-900">Gift card</h3>
          <button onClick={onClose} className="p-1 rounded hover:bg-slate-100"><X size={18} /></button>
        </div>
        {loading || !card ? (
          <div className="py-16 flex justify-center"><Loader2 className="animate-spin text-slate-400" /></div>
        ) : (
          <div className="p-5 space-y-5">
            <div className="rounded-xl border border-slate-200 p-4 bg-slate-50">
              <div className="flex items-center justify-between">
                <div className="text-xs text-slate-500 uppercase tracking-wider">Code (masked)</div>
                <span className="text-[10px] uppercase tracking-wider text-amber-700 bg-amber-100 px-2 py-0.5 rounded-full font-semibold">Hashed for security</span>
              </div>
              <div className="flex items-center justify-between gap-2 mt-1">
                <span className="font-mono text-base text-slate-900 truncate">{card.masked_code}</span>
                <div className="flex items-center gap-1 shrink-0">
                  <button onClick={copy} className="text-xs px-2 py-1 rounded border border-slate-200 hover:bg-white flex items-center gap-1" title="Copy masked code">
                    {copied ? <><Check size={12} className="text-emerald-600" /> Copied</> : <><Copy size={12} /> Copy</>}
                  </button>
                  <button onClick={copyLast4} className="text-xs px-2 py-1 rounded border border-slate-200 hover:bg-white flex items-center gap-1" title="Copy just the last 4 digits">
                    Last 4
                  </button>
                </div>
              </div>
              <p className="text-xs text-slate-500 mt-2 leading-relaxed">
                <strong>The full code is never stored on our servers.</strong> It was shown only once at issuance and emailed to the recipient.
                Use <em>Resend voucher</em> below to email the recipient again (the email shows the masked code only — they still have the full code in their original message).
                The last 4 digits help you confirm the right card when a customer reads theirs to you.
              </p>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <Field label="Original amount"><div className="text-sm font-semibold">{fmtMoney(card.original_amount, card.currency)}</div></Field>
              <Field label="Balance"><div className="text-sm font-semibold text-emerald-700">{fmtMoney(card.balance, card.currency)}</div></Field>
              <Field label="Status"><StatusPill status={card.status} /></Field>
              <Field label="Created"><div className="text-sm">{new Date(card.created_at).toLocaleDateString()}</div></Field>
              <Field label="Recipient"><div className="text-sm">{card.recipient_name}</div></Field>
              <Field label="Email"><div className="text-sm break-all">{card.recipient_email || '—'}</div></Field>
              <Field label="Sender"><div className="text-sm">{card.sender_name || '—'}</div></Field>
              <Field label="Expires"><div className="text-sm">{card.expires_at ? new Date(card.expires_at).toLocaleDateString() : 'Never'}</div></Field>
            </div>

            {card.personal_message && (
              <div>
                <div className="text-xs font-semibold text-slate-700 mb-1">Personal message</div>
                <div className="text-sm italic text-slate-600 border-l-2 border-orange-200 pl-3">{card.personal_message}</div>
              </div>
            )}

            <div className="flex flex-wrap gap-2">
              <a href={`/api/gift-cards/${card.id}/voucher`} target="_blank" rel="noopener noreferrer" className="text-sm px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-slate-50 flex items-center gap-1"><Download size={14} /> Voucher PDF</a>
              {card.recipient_email && (
                <button onClick={resendEmail} className="text-sm px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-slate-50 flex items-center gap-1" title="Email the masked voucher + balance reminder to the recipient"><Mail size={14} /> Resend voucher</button>
              )}
              <button onClick={refundCard} className="text-sm px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-slate-50 flex items-center gap-1"><RefreshCw size={14} /> Refund</button>
              {card.status !== 'void' && (
                <button onClick={voidCard} className="text-sm px-3 py-1.5 rounded-lg border border-red-200 text-red-600 hover:bg-red-50 flex items-center gap-1"><Trash2 size={14} /> Void</button>
              )}
            </div>

            <div>
              <div className="text-xs font-semibold text-slate-700 uppercase tracking-wide mb-2">Ledger</div>
              {ledger.length === 0 ? (
                <div className="text-sm text-slate-500 py-3">No activity yet.</div>
              ) : (
                <div className="rounded-lg border border-slate-200 divide-y divide-slate-100">
                  {ledger.map((e) => (
                    <div key={e.id} className="px-3 py-2 flex items-start justify-between gap-2 text-sm">
                      <div>
                        <div className="font-medium text-slate-900 capitalize">{e.entry_type.replace(/_/g, ' ')}</div>
                        <div className="text-xs text-slate-500">{new Date(e.created_at).toLocaleString()}</div>
                        {e.note && <div className="text-xs text-slate-500">{e.note}</div>}
                      </div>
                      <div className="text-right">
                        <div className={`font-semibold ${['issuance', 'refund'].includes(e.entry_type) ? 'text-emerald-700' : 'text-slate-900'}`}>
                          {['issuance', 'refund'].includes(e.entry_type) ? '+' : '−'}{fmtMoney(Math.abs(e.amount), card.currency)}
                        </div>
                        <div className="text-xs text-slate-500">bal {fmtMoney(e.balance_after, card.currency)}</div>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function StatCard({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) {
  return (
    <div className={`rounded-xl p-4 border ${highlight ? 'border-orange-200 bg-orange-50' : 'border-slate-200 bg-white'}`}>
      <div className="text-xs text-slate-500 uppercase tracking-wide">{label}</div>
      <div className={`text-xl font-bold ${highlight ? 'text-orange-700' : 'text-slate-900'}`}>{value}</div>
    </div>
  );
}

function StatusPill({ status }: { status: string }) {
  const map: Record<string, string> = {
    active: 'bg-emerald-100 text-emerald-700',
    redeemed: 'bg-slate-100 text-slate-700',
    expired: 'bg-amber-100 text-amber-700',
    void: 'bg-red-100 text-red-700',
  };
  return <span className={`text-xs px-2 py-0.5 rounded-full font-semibold ${map[status] || 'bg-slate-100'}`}>{status}</span>;
}

function IssueDialog({ settings, onClose, onIssued }: {
  settings: Settings | null;
  onClose: () => void;
  onIssued: (card: { code: string; masked_code: string; original_amount: number; currency: string }) => void;
}) {
  const [amount, setAmount] = useState<number>(50);
  const [recipientName, setRecipientName] = useState('');
  const [recipientEmail, setRecipientEmail] = useState('');
  const [senderName, setSenderName] = useState('');
  const [personalMessage, setPersonalMessage] = useState('');
  const [sendEmail, setSendEmail] = useState(true);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Seed the amount from the parent-provided settings as soon as it lands.
  useEffect(() => {
    if (settings?.denominations?.[0]) setAmount(Number(settings.denominations[0]));
  }, [settings]);

  const submit = async () => {
    if (!recipientName.trim()) { setError('Recipient name is required'); return; }
    if (sendEmail && !recipientEmail.trim()) { setError('Recipient email is required to send the email'); return; }
    setSubmitting(true);
    setError(null);
    try {
      const res = await fetch('/api/gift-cards', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          amount,
          recipient_name: recipientName.trim(),
          recipient_email: recipientEmail.trim() || null,
          sender_name: senderName.trim() || null,
          personal_message: personalMessage.trim() || null,
          send_email: sendEmail,
        }),
      });
      const json = await res.json();
      if (!res.ok) throw new Error(json?.error || 'Failed to issue card');
      onIssued(json.card);
    } catch (err) {
      setError((err as Error).message);
    } finally {
      setSubmitting(false);
    }
  };

  if (!settings) {
    return (
      <Dialog title="Issue gift card" onClose={onClose}>
        <div className="py-8 flex justify-center"><Loader2 className="animate-spin" /></div>
      </Dialog>
    );
  }

  return (
    <Dialog title="Issue gift card" onClose={onClose}>
      <div className="space-y-3">
        <div>
          <label className="text-xs font-semibold text-slate-700 mb-1 block">Amount</label>
          <div className="flex flex-wrap gap-2 mb-2">
            {settings.denominations.map((d) => (
              <button
                key={d}
                onClick={() => setAmount(Number(d))}
                type="button"
                className={`px-3 py-1.5 rounded-lg text-sm font-semibold border ${amount === Number(d) ? 'border-orange-500 bg-orange-50 text-orange-700' : 'border-slate-200 text-slate-600'}`}
              >
                {fmtMoney(Number(d), settings.currency)}
              </button>
            ))}
          </div>
          {settings.custom_amount_enabled && (
            <input
              type="number"
              step="0.01"
              min={settings.custom_min}
              max={settings.custom_max}
              value={amount}
              onChange={(e) => setAmount(Number(e.target.value))}
              className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm"
              placeholder={`Custom amount (${settings.custom_min}–${settings.custom_max})`}
            />
          )}
        </div>
        <div>
          <label className="text-xs font-semibold text-slate-700 mb-1 block">Recipient name *</label>
          <input value={recipientName} onChange={(e) => setRecipientName(e.target.value)} className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm" />
        </div>
        <div>
          <label className="text-xs font-semibold text-slate-700 mb-1 block">Recipient email{sendEmail ? ' *' : ''}</label>
          <input type="email" value={recipientEmail} onChange={(e) => setRecipientEmail(e.target.value)} className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm" />
        </div>
        <div>
          <label className="text-xs font-semibold text-slate-700 mb-1 block">Sender name</label>
          <input value={senderName} onChange={(e) => setSenderName(e.target.value)} className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm" />
        </div>
        <div>
          <label className="text-xs font-semibold text-slate-700 mb-1 block">Personal message</label>
          <textarea value={personalMessage} onChange={(e) => setPersonalMessage(e.target.value)} className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm" rows={2} maxLength={300} />
        </div>
        <label className="flex items-center gap-2 text-sm">
          <input type="checkbox" checked={sendEmail} onChange={(e) => setSendEmail(e.target.checked)} />
          Email the voucher to the recipient now
        </label>

        {error && <div className="text-sm text-red-600 flex items-center gap-1"><AlertCircle size={14} /> {error}</div>}

        <div className="flex gap-2 justify-end pt-2">
          <button onClick={onClose} type="button" className="px-3 py-2 rounded-lg text-sm text-slate-600">Cancel</button>
          <button onClick={submit} disabled={submitting} type="button" className="px-4 py-2 rounded-lg bg-orange-500 hover:bg-orange-600 text-white text-sm font-semibold disabled:bg-slate-300">
            {submitting ? 'Issuing…' : `Issue ${fmtMoney(amount || 0, settings.currency)}`}
          </button>
        </div>
      </div>
    </Dialog>
  );
}

function CodeRevealDialog({ card, onClose }: { card: { code: string; masked_code: string; amount: number; currency: string }; onClose: () => void }) {
  return (
    <Dialog title="Card issued" onClose={onClose}>
      <div className="text-center py-4">
        <div className="text-xs text-slate-500 mb-1 uppercase tracking-wider">Worth</div>
        <div className="text-3xl font-bold text-slate-900 mb-4">{fmtMoney(card.amount, card.currency)}</div>
        <div className="text-xs text-slate-500 mb-1 uppercase tracking-wider">Code (only shown once)</div>
        <div className="font-mono text-xl bg-slate-100 rounded-lg px-4 py-3 inline-block">{card.code}</div>
        <p className="text-xs text-slate-500 mt-3">Make a note of this code — it will not be shown again. The recipient has been emailed (if applicable).</p>
        <button onClick={onClose} className="mt-4 px-4 py-2 rounded-lg bg-slate-900 text-white text-sm font-semibold">Done</button>
      </div>
    </Dialog>
  );
}

function Dialog({ title, onClose, children }: { title: string; onClose: () => void; children: React.ReactNode }) {
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4" onClick={onClose}>
      <div className="bg-white rounded-2xl shadow-xl max-w-md w-full p-5 max-h-[90vh] overflow-auto" onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center justify-between mb-4">
          <h3 className="text-lg font-bold text-slate-900">{title}</h3>
          <button onClick={onClose} className="p-1 rounded hover:bg-slate-100"><X size={18} /></button>
        </div>
        {children}
      </div>
    </div>
  );
}

// ---------- Settings tab ----------

function SettingsTab({ settings, setSettings }: {
  settings: Settings | null;
  setSettings: React.Dispatch<React.SetStateAction<Settings | null>>;
}) {
  const [saving, setSaving] = useState(false);
  const [denomInput, setDenomInput] = useState('');

  // Mirror the parent-fetched settings into the editable denomInput once it
  // arrives. No additional fetch — the parent (GiftCardsAdmin) is the single
  // source of truth.
  useEffect(() => {
    if (settings) setDenomInput((settings.denominations || []).join(', '));
  }, [settings]);

  const save = async () => {
    if (!settings) return;
    setSaving(true);
    try {
      const denominations = denomInput.split(',').map((s) => Number(s.trim())).filter((n) => Number.isFinite(n) && n > 0);
      const res = await fetch('/api/gift-cards/settings', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ...settings, denominations }),
      });
      if (!res.ok) {
        const json = await res.json().catch(() => ({}));
        toast.error(json?.error || 'Save failed');
        return;
      }
      toast.success('Settings saved');
      const j = await res.json();
      setSettings(j.settings);
    } finally {
      setSaving(false);
    }
  };

  if (!settings) return <div className="py-16 flex justify-center text-slate-500"><Loader2 className="animate-spin mr-2" /> Loading…</div>;

  const update = (patch: Partial<Settings>) => setSettings((s) => ({ ...(s as Settings), ...patch }));

  return (
    <div className="grid lg:grid-cols-[minmax(0,1fr)_360px] gap-6 items-start">
      <div className="space-y-6 min-w-0">
      <Section title="Issuance">
        <Field label="Enabled">
          <input type="checkbox" checked={settings.enabled} onChange={(e) => update({ enabled: e.target.checked })} />
        </Field>
        <Field label="Preset denominations (comma-separated)">
          <input className="input" value={denomInput} onChange={(e) => setDenomInput(e.target.value)} placeholder="10, 25, 50, 100" />
        </Field>
        <Field label="Allow custom amount">
          <input type="checkbox" checked={settings.custom_amount_enabled} onChange={(e) => update({ custom_amount_enabled: e.target.checked })} />
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label="Custom min">
            <input type="number" className="input" value={settings.custom_min} onChange={(e) => update({ custom_min: Number(e.target.value) })} />
          </Field>
          <Field label="Custom max">
            <input type="number" className="input" value={settings.custom_max} onChange={(e) => update({ custom_max: Number(e.target.value) })} />
          </Field>
        </div>
        <Field label="Default expiry (months, blank = no expiry)">
          <input type="number" className="input" value={settings.default_expiry_months ?? ''} onChange={(e) => update({ default_expiry_months: e.target.value ? Number(e.target.value) : null })} />
        </Field>
      </Section>

      <Section title="Code generation">
        <div className="grid grid-cols-2 gap-3">
          <Field label="Code prefix">
            <input className="input" value={settings.code_prefix} onChange={(e) => update({ code_prefix: e.target.value.toUpperCase() })} maxLength={6} />
          </Field>
          <Field label="Code length (8–20)">
            <input type="number" className="input" min={8} max={20} value={settings.code_length} onChange={(e) => update({ code_length: Number(e.target.value) })} />
          </Field>
        </div>
      </Section>

      <Section title="Branding">
        <Field label="Brand color">
          <input type="color" value={settings.brand_primary_color} onChange={(e) => update({ brand_primary_color: e.target.value })} className="h-10 w-16 rounded" />
        </Field>
        <Field label="Email opening line (optional)">
          <input className="input" value={settings.email_from_line ?? ''} onChange={(e) => update({ email_from_line: e.target.value })} placeholder="From the team at Acme Bistro" />
        </Field>
        <Field label="Default voucher message">
          <textarea className="input" rows={2} value={settings.message_template} onChange={(e) => update({ message_template: e.target.value })} />
        </Field>
        <Field label="Show full code on PDF voucher">
          <input type="checkbox" checked={settings.show_full_code_on_voucher} onChange={(e) => update({ show_full_code_on_voucher: e.target.checked })} />
        </Field>
      </Section>

      <Section title="Redemption">
        <Field label="Apply to">
          <select className="input" value={settings.redemption_rule} onChange={(e) => update({ redemption_rule: e.target.value as 'subtotal' | 'total' })}>
            <option value="subtotal">Subtotal only (does not offset taxes)</option>
            <option value="total">Total (includes taxes)</option>
          </select>
        </Field>
        <Field label="Stack with coupons">
          <input type="checkbox" checked={settings.stack_with_coupons} onChange={(e) => update({ stack_with_coupons: e.target.checked })} />
        </Field>
        <Field label="Stack with loyalty points">
          <input type="checkbox" checked={settings.stack_with_loyalty} onChange={(e) => update({ stack_with_loyalty: e.target.checked })} />
        </Field>
      </Section>

      <div className="flex justify-end">
        <button onClick={save} disabled={saving} className="px-5 py-2.5 rounded-lg bg-orange-500 hover:bg-orange-600 text-white text-sm font-semibold disabled:bg-slate-300">
          {saving ? 'Saving…' : 'Save settings'}
        </button>
      </div>
      </div>

      <aside className="lg:sticky lg:top-4 space-y-4">
        <div className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Live preview</div>
        <SampleVoucherPreview settings={settings} />
        <SampleEmailPreview settings={settings} />
        <p className="text-xs text-slate-500 leading-relaxed">
          These are previews only — your edits are not saved until you click <strong>Save settings</strong>.
          Real cards include a unique cleartext code shown once at issuance.
        </p>
      </aside>

      <style jsx>{`
        :global(.input) {
          width: 100%;
          padding: 8px 12px;
          font-size: 14px;
          border: 1px solid #e2e8f0;
          border-radius: 8px;
          background: white;
        }
      `}</style>
    </div>
  );
}

// ---------- Live previews (Settings tab) ----------

function SampleVoucherPreview({ settings }: { settings: Settings }) {
  const sampleAmount = settings.denominations?.[0] ?? 50;
  const sampleCode = `${(settings.code_prefix || 'GC')}••••••${'A1B2'}`;
  const fullSampleCode = `${(settings.code_prefix || 'GC')}X7K9P3M2A1B2`;
  const codeOnVoucher = settings.show_full_code_on_voucher ? fullSampleCode : sampleCode;
  return (
    <div className="rounded-2xl overflow-hidden border border-slate-200 shadow-sm bg-white">
      <div className="px-4 py-2 bg-slate-50 border-b border-slate-200 text-xs font-semibold text-slate-600">
        Sample voucher (PDF + email card)
      </div>
      <div className="p-4">
        <div
          className="rounded-xl p-5 text-white relative overflow-hidden"
          style={{ background: `linear-gradient(135deg, ${settings.brand_primary_color} 0%, ${shade(settings.brand_primary_color, -25)} 100%)` }}
        >
          <div className="text-[10px] uppercase tracking-[0.2em] opacity-80">Gift Card</div>
          <div className="mt-1 text-3xl font-bold">{fmtMoney(sampleAmount, settings.currency)}</div>
          <div className="mt-3 text-[10px] uppercase tracking-wider opacity-80">Code</div>
          <div className="font-mono text-base tracking-widest mt-0.5">{codeOnVoucher}</div>
          <div className="mt-4 text-xs italic opacity-90 line-clamp-3">
            {settings.message_template || 'Enjoy a meal on us!'}
          </div>
          <div className="mt-3 text-[10px] opacity-80">
            For: Sample Recipient · {settings.default_expiry_months
              ? `Expires in ${settings.default_expiry_months} months`
              : 'No expiry'}
          </div>
        </div>
      </div>
    </div>
  );
}

function SampleEmailPreview({ settings }: { settings: Settings }) {
  const amount = settings.denominations?.[0] ?? 50;
  const opening = settings.email_from_line || 'A gift just for you';
  return (
    <div className="rounded-2xl overflow-hidden border border-slate-200 shadow-sm bg-white">
      <div className="px-4 py-2 bg-slate-50 border-b border-slate-200 text-xs font-semibold text-slate-600">
        Sample issuance email
      </div>
      <div className="p-4 space-y-3">
        <div className="text-xs text-slate-500">
          <div><strong>From:</strong> Your restaurant</div>
          <div><strong>To:</strong> sample@example.com</div>
          <div><strong>Subject:</strong> You&apos;ve received a gift card</div>
        </div>
        <div className="rounded-xl border border-slate-100 overflow-hidden">
          <div className="h-2" style={{ background: settings.brand_primary_color }} />
          <div className="p-4 text-sm text-slate-700 space-y-3">
            <div className="text-base font-semibold text-slate-900">{opening}</div>
            <div>Hi Sample Recipient,</div>
            <div>You&apos;ve received a {fmtMoney(amount, settings.currency)} gift card to use on any order.</div>
            <div className="rounded-lg p-3 text-center" style={{ background: `${settings.brand_primary_color}15`, border: `1px solid ${settings.brand_primary_color}40` }}>
              <div className="text-[10px] uppercase tracking-wider text-slate-500">Your code</div>
              <div className="font-mono text-base tracking-widest font-bold mt-1" style={{ color: settings.brand_primary_color }}>
                {settings.code_prefix || 'GC'}X7K9P3M2A1B2
              </div>
            </div>
            {settings.message_template && (
              <div className="italic text-slate-600 border-l-2 pl-3" style={{ borderColor: settings.brand_primary_color }}>
                {settings.message_template}
              </div>
            )}
            <div className="text-xs text-slate-500">
              Apply at checkout — your remaining balance carries over to future orders.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// Lighten/darken a hex color by `percent` (positive=lighter, negative=darker)
function shade(hex: string, percent: number): string {
  const m = /^#?([a-f\d]{6})$/i.exec(hex || '');
  if (!m) return hex;
  const num = parseInt(m[1], 16);
  const amt = Math.round(2.55 * percent);
  const r = Math.min(255, Math.max(0, ((num >> 16) & 0xff) + amt));
  const g = Math.min(255, Math.max(0, ((num >> 8) & 0xff) + amt));
  const b = Math.min(255, Math.max(0, (num & 0xff) + amt));
  return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
}

function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="rounded-xl border border-slate-200 bg-white p-5">
      <h3 className="font-semibold text-slate-900 mb-3">{title}</h3>
      <div className="space-y-3">{children}</div>
    </div>
  );
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div>
      <label className="text-xs font-semibold text-slate-700 mb-1 block">{label}</label>
      {children}
    </div>
  );
}
