import { useCallback, useMemo, useRef, useState } from 'react';
import {
  AllCommunityModule, ModuleRegistry, themeQuartz,
  type ColDef, type ColumnState, type GridReadyEvent, type RowDoubleClickedEvent,
} from 'ag-grid-community';
import { AgGridReact } from 'ag-grid-react';
import { Columns3, FilterX, Star } from 'lucide-react';
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Badge } from '@/components/ui/badge';
import type { WorkedBeforeView, QSOForm } from '@/types';
import { COL_CATALOG, GROUP_ORDER } from './RecentQSOsGrid';
import { QSOContextMenu, type QSOMenuState } from './QSOContextMenu';
import { loadLocal, loadRemote, saveState, seedLocal } from '@/lib/gridPrefs';

ModuleRegistry.registerModules([AllCommunityModule]);

const hamlogTheme = themeQuartz.withParams({
  fontFamily: 'inherit',
  fontSize: 12.5,
  backgroundColor: '#faf6ea',
  foregroundColor: '#2a2419',
  headerBackgroundColor: '#e8dfc9',
  headerTextColor: '#5a4f3a',
  headerFontWeight: 600,
  oddRowBackgroundColor: '#f5efe0',
  rowHoverColor: '#ecdcb4',
  selectedRowBackgroundColor: '#f0d9a8',
  borderColor: '#c8b994',
  rowBorder: { color: '#d8c9a8', width: 1 },
  columnBorder: { color: '#d8c9a8', width: 1 },
  cellHorizontalPadding: 10,
  rowHeight: 30,
  headerHeight: 32,
  spacing: 4,
  accentColor: '#b8410c',
  iconSize: 12,
});

type WorkedEntry = QSOForm; // entries are now full QSO records

type Props = {
  wb: WorkedBeforeView | null;
  busy: boolean;
  currentCall: string;
  onRowDoubleClicked?: (q: QSOForm) => void;
  onUpdateFromCty?: (ids: number[]) => void;
  onUpdateFromQRZ?: (ids: number[]) => void;
  onUpdateFromClublog?: (ids: number[]) => void;
  onSendTo?: (service: string, ids: number[]) => void;
  onSendRecording?: (ids: number[]) => void;
  onSendEQSL?: (ids: number[]) => void;
};

const COL_STATE_KEY = 'hamlog.workedBeforeColState.v2';

function fmtDate(s: any): string {
  if (!s) return '';
  const d = new Date(s);
  if (isNaN(d.getTime())) return '';
  const p = (n: number) => String(n).padStart(2, '0');
  return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())}`;
}

export function WorkedBeforeGrid({ wb, busy, currentCall, onRowDoubleClicked, onUpdateFromCty, onUpdateFromQRZ, onUpdateFromClublog, onSendTo, onSendRecording, onSendEQSL }: Props) {
  const gridRef = useRef<any>(null);
  const [pickerOpen, setPickerOpen] = useState(false);
  const [menu, setMenu] = useState<QSOMenuState>(null);

  function handleRowDoubleClicked(e: RowDoubleClickedEvent<WorkedEntry>) {
    if (e.data && onRowDoubleClicked) onRowDoubleClicked(e.data);
  }
  function onCellContextMenu(e: any) {
    const ev = e.event as MouseEvent | undefined;
    ev?.preventDefault();
    const api = gridRef.current?.api;
    if (!api) return;
    if (e.node && !e.node.isSelected()) {
      api.deselectAll();
      e.node.setSelected(true);
    }
    const ids = (api.getSelectedRows() as WorkedEntry[])
      .map((r) => r.id as number)
      .filter((n) => !!n);
    if (ids.length === 0) return;
    setMenu({ x: ev?.clientX ?? 0, y: ev?.clientY ?? 0, ids });
  }

  const hasCall = currentCall.trim() !== '';
  const count = wb?.count ?? 0;
  const entries = wb?.entries ?? [];

  const columnDefs = useMemo<ColDef<WorkedEntry>[]>(() => COL_CATALOG.map((c) => {
    const { group: _g, label: _l, defaultVisible, ...rest } = c;
    return { ...rest, hide: !defaultVisible };
  }), []);

  const defaultColDef = useMemo<ColDef>(() => ({
    sortable: true, resizable: true, filter: true, suppressMovable: false,
  }), []);

  function onGridReady(e: GridReadyEvent) {
    const local = loadLocal(COL_STATE_KEY);
    if (local) e.api.applyColumnState({ state: local as ColumnState[], applyOrder: true });
    loadRemote(COL_STATE_KEY).then((remote) => {
      if (remote && !local) {
        e.api.applyColumnState({ state: remote as ColumnState[], applyOrder: true });
        seedLocal(COL_STATE_KEY, remote);
      }
    });
  }
  const saveColumnState = useCallback(() => {
    const state = gridRef.current?.api?.getColumnState();
    if (state) saveState(COL_STATE_KEY, state);
  }, []);

  function isColVisible(colId: string): boolean {
    const col = gridRef.current?.api?.getColumn(colId);
    return col ? col.isVisible() : !!COL_CATALOG.find((c) => c.colId === colId)?.defaultVisible;
  }
  function setColVisible(colId: string, visible: boolean) {
    const api = gridRef.current?.api;
    if (!api) return;
    api.setColumnsVisible([colId], visible);
    saveColumnState();
  }
  function showAll(group?: string) {
    const api = gridRef.current?.api;
    if (!api) return;
    const ids = COL_CATALOG.filter((c) => !group || c.group === group).map((c) => c.colId!);
    api.setColumnsVisible(ids, true);
    saveColumnState();
  }
  function hideAll(group?: string) {
    const api = gridRef.current?.api;
    if (!api) return;
    const ids = COL_CATALOG.filter((c) => !group || c.group === group).map((c) => c.colId!);
    api.setColumnsVisible(ids, false);
    saveColumnState();
  }
  function resetDefaults() {
    const api = gridRef.current?.api;
    if (!api) return;
    const visible = COL_CATALOG.filter((c) => c.defaultVisible).map((c) => c.colId!);
    const hidden = COL_CATALOG.filter((c) => !c.defaultVisible).map((c) => c.colId!);
    api.setColumnsVisible(visible, true);
    api.setColumnsVisible(hidden, false);
    saveColumnState();
  }

  // Empty / loading / no-call states.
  if (!hasCall) {
    return (
      <div className="flex-1 flex flex-col items-center justify-center gap-2 p-6 text-center text-xs text-muted-foreground">
        Type a callsign in the entry strip to see prior contacts.
      </div>
    );
  }
  if (busy && count === 0) {
    return (
      <div className="flex-1 flex items-center justify-center text-xs text-muted-foreground italic">
        checking…
      </div>
    );
  }
  if (count === 0) {
    return (
      <div className="flex-1 flex flex-col items-center justify-center gap-2 p-6 text-center text-xs text-muted-foreground">
        <Star className="size-8 text-primary fill-current" />
        <div className="text-2xl font-bold text-primary tracking-wider">NEW</div>
        <div>No prior QSO with <span className="font-mono font-semibold text-foreground">{currentCall.toUpperCase()}</span>.</div>
      </div>
    );
  }

  return (
    <>
      <div className="flex items-center gap-3 px-3 py-1.5 border-b border-border/60 bg-muted/30">
        <div className="flex items-baseline gap-2">
          <span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">Worked before</span>
          <span className="font-mono text-sm font-bold text-primary tracking-wider">{currentCall.toUpperCase()}</span>
          <Badge variant="accent" className="font-mono text-[11px] tracking-wider">{count}×</Badge>
        </div>
        <div className="text-[11px] text-muted-foreground">
          First: <strong className="text-foreground font-semibold">{fmtDate(wb?.first)}</strong> ·{' '}
          Last: <strong className="text-foreground font-semibold">{fmtDate(wb?.last)}</strong>
        </div>
        {wb?.dxcc_name && (
          <div className="text-[11px] text-muted-foreground">
            DXCC: <strong className="text-foreground font-semibold">{wb.dxcc_name}</strong>
            {typeof wb.dxcc_count === 'number' && wb.dxcc_count > 0 && (
              <span> · {wb.dxcc_count} entity QSOs</span>
            )}
          </div>
        )}
        <div className="flex-1" />
        <Button variant="ghost" size="sm" className="h-7 text-[11px]" onClick={() => gridRef.current?.api?.setFilterModel(null)}
          title="Clear all column filters">
          <FilterX className="size-3.5" /> Clear filters
        </Button>
        <Button variant="ghost" size="sm" className="h-7 text-[11px]" onClick={() => setPickerOpen(true)}>
          <Columns3 className="size-3.5" /> Columns
        </Button>
      </div>

      <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>
        <div style={{ position: 'absolute', inset: 0 }}>
          <AgGridReact<WorkedEntry>
            ref={gridRef}
            theme={hamlogTheme}
            rowData={entries}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            onGridReady={onGridReady}
            onColumnResized={saveColumnState}
            onColumnMoved={saveColumnState}
            onColumnPinned={saveColumnState}
            onColumnVisible={saveColumnState}
            onSortChanged={saveColumnState}
            onRowDoubleClicked={handleRowDoubleClicked}
            onCellContextMenu={onCellContextMenu}
            preventDefaultOnContextMenu
            rowSelection={{ mode: 'multiRow', checkboxes: false, headerCheckbox: false, enableClickSelection: true }}
            animateRows={false}
            suppressCellFocus
            getRowId={(p) => String((p.data as any).id)}
          />
        </div>
      </div>

      <QSOContextMenu
        menu={menu}
        onClose={() => setMenu(null)}
        onUpdateFromCty={(ids) => onUpdateFromCty?.(ids)}
        onUpdateFromQRZ={(ids) => onUpdateFromQRZ?.(ids)}
        onUpdateFromClublog={onUpdateFromClublog}
        onSendTo={onSendTo}
        onSendRecording={onSendRecording}
        onSendEQSL={onSendEQSL}
      />

      {count > entries.length && (
        <div className="text-center py-1 text-[11px] italic text-muted-foreground border-t border-border/60 bg-muted/30">
          + {count - entries.length} older QSOs (not shown — capped for performance)
        </div>
      )}

      <Dialog open={pickerOpen} onOpenChange={setPickerOpen}>
        <DialogContent className="max-w-2xl">
          <DialogHeader>
            <DialogTitle>Worked-before columns</DialogTitle>
            <DialogDescription>
              Pick the columns you want visible in the Worked-before table.
            </DialogDescription>
          </DialogHeader>
          <div className="grid grid-cols-2 gap-4 max-h-[60vh] overflow-y-auto px-5 py-3">
            {GROUP_ORDER.map((group) => {
              const cols = COL_CATALOG.filter((c) => c.group === group);
              if (cols.length === 0) return null;
              return (
                <div key={group} className="rounded-md border border-border p-2.5">
                  <div className="flex items-center justify-between mb-2 pb-1.5 border-b border-border/60">
                    <span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">{group}</span>
                    <div className="flex gap-0.5">
                      <button className="text-[10px] text-primary hover:underline px-1" onClick={() => showAll(group)}>all</button>
                      <button className="text-[10px] text-muted-foreground hover:underline px-1" onClick={() => hideAll(group)}>none</button>
                    </div>
                  </div>
                  <div className="flex flex-col gap-1">
                    {cols.map((c) => (
                      <label key={c.colId} className="flex items-center gap-2 text-xs cursor-pointer hover:bg-accent/30 rounded px-1 py-0.5">
                        <Checkbox
                          checked={isColVisible(c.colId!)}
                          onCheckedChange={(v) => setColVisible(c.colId!, !!v)}
                        />
                        {c.label}
                      </label>
                    ))}
                  </div>
                </div>
              );
            })}
          </div>
          <DialogFooter>
            <Button variant="ghost" size="sm" onClick={resetDefaults}>Reset to defaults</Button>
            <Button size="sm" onClick={() => setPickerOpen(false)}>Done</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
