import { useEffect, useState } from 'react';
import { PickerShell } from '../core/PickerShell';
import { useZino } from '../../api/provider';

export interface LookupValue {
  [col: string]: unknown;
}

export interface LookupFieldProps {
  label?: string;
  required?: boolean;
  templateUid: string;
  /** Columns joined to form the option label. */
  displayCols: string[];
  /** Columns persisted on the value object. */
  storageCols: string[];
  activityId: string;
  fieldId: string;
  instanceId?: number | string;
  value: LookupValue | null;
  onChange: (v: LookupValue | null) => void;
}

type Row = Record<string, unknown>;

/** Searchable RDBMS-lookup picker (owner agent etc.). Mirrors the renderer's
 *  FFLookupField: projects the picked row onto storage + display columns.
 *  Renders through the shared PickerShell so it's identical to SelectField. */
export function LookupField({
  label,
  required,
  templateUid,
  displayCols,
  storageCols,
  activityId,
  fieldId,
  instanceId,
  value,
  onChange,
}: LookupFieldProps) {
  const { client } = useZino();
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState('');
  const [rows, setRows] = useState<Row[]>([]);
  const [loading, setLoading] = useState(false);

  const labelOf = (src: LookupValue | Row | null) =>
    src
      ? displayCols
          .map((c) => src[c])
          .filter((v) => v !== null && v !== undefined && v !== '')
          .join(', ')
      : '';

  // Collapse rows that project to the same stored value — e.g. many branches
  // sharing one region show "North" once. Lookups whose storage carries a
  // unique id never collapse.
  const dedupe = (list: Row[]) => {
    const cols = storageCols.length ? storageCols : displayCols;
    const seen = new Set<string>();
    return list.filter((row) => {
      const sig = JSON.stringify(cols.map((c) => row[c] ?? null));
      if (seen.has(sig)) return false;
      seen.add(sig);
      return true;
    });
  };

  // Debounced fetch while the dropdown is open.
  useEffect(() => {
    if (!open) return;
    let live = true;
    setLoading(true);
    const t = setTimeout(() => {
      client
        .lookupRecords(templateUid, { activityId, fieldId, instanceId, search, limit: 50 })
        .then((r) => {
          if (live) setRows(dedupe(r.records ?? []));
        })
        .catch(() => {
          if (live) setRows([]);
        })
        .finally(() => {
          if (live) setLoading(false);
        });
    }, 220);
    return () => {
      live = false;
      clearTimeout(t);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, search, templateUid, activityId, fieldId, instanceId, client]);

  function pick(row: Row) {
    const stored: LookupValue = {};
    storageCols.forEach((c) => (stored[c] = row[c] ?? null));
    displayCols.forEach((c) => {
      if (!(c in stored)) stored[c] = row[c] ?? null;
    });
    onChange(stored);
  }

  return (
    <PickerShell<Row>
      label={label}
      required={required}
      displayLabel={labelOf(value)}
      items={rows}
      renderItem={(row) => labelOf(row) || 'Row'}
      itemKey={(_row, i) => i}
      onPick={pick}
      onClear={() => onChange(null)}
      search={search}
      onSearch={setSearch}
      loading={loading}
      onOpenChange={(o) => {
        setOpen(o);
        if (!o) setSearch('');
      }}
    />
  );
}
