'use client';

/**
 * Inline field-history surface for detail pages.
 *
 * The pattern:
 *
 *   1. Wrap the detail page (or just the section containing editable
 *      fields) in <FieldHistoryProvider scope={{ type, id }} />. The
 *      provider fires a single GET for every recorded override, keyed
 *      by entity, and exposes a Map<fieldPath, HistoryRow[]> via context.
 *
 *   2. Pass `historyPath` to any InlineEditableField that maps to a
 *      bindable path (see src/lib/templates/bindable-fields.ts). The
 *      field renders a small clock icon next to the value when at least
 *      one history row exists for that path. Click → popover with the
 *      reverse-chronological diff list.
 *
 * Fields without `historyPath`, or fields whose path has zero history
 * rows, render nothing extra - the surface is purely additive.
 */

import { createContext, useContext, useMemo, type ReactNode } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Clock } from 'lucide-react';
import { formatDistanceToNow } from 'date-fns';

import { apiFetch } from '@/lib/api/client';
import { Button } from '@/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { ScrollArea } from '@/components/ui/scroll-area';
import { getBindableField } from '@/lib/templates/bindable-fields';
import { cn } from '@/lib/utils';

export interface FieldHistoryScope {
  type: 'interest' | 'client' | 'yacht';
  id: string;
}

export interface FieldHistoryRow {
  id: string;
  fieldPath: string;
  oldValue: unknown;
  newValue: unknown;
  source: string;
  createdAt: string;
}

interface ContextValue {
  byPath: Map<string, FieldHistoryRow[]>;
  isLoading: boolean;
}

const FieldHistoryContext = createContext<ContextValue>({
  byPath: new Map(),
  isLoading: false,
});

interface ProviderProps {
  scope: FieldHistoryScope | null;
  children: ReactNode;
}

export function FieldHistoryProvider({ scope, children }: ProviderProps) {
  const { data, isLoading } = useQuery({
    enabled: scope !== null,
    queryKey: ['field-history', scope?.type, scope?.id],
    queryFn: async () => {
      if (!scope) return [] as FieldHistoryRow[];
      const url = `/api/v1/${scope.type}s/${scope.id}/field-history`;
      const res = await apiFetch<{ data: FieldHistoryRow[] }>(url);
      return res.data;
    },
    // Field history is small + read-mostly. 30s is plenty fresh for the
    // common case where the rep edits a field and wants to see the
    // history reflect immediately - react-query refetches on focus.
    staleTime: 30_000,
  });

  const byPath = useMemo(() => {
    const map = new Map<string, FieldHistoryRow[]>();
    for (const row of data ?? []) {
      const arr = map.get(row.fieldPath) ?? [];
      arr.push(row);
      map.set(row.fieldPath, arr);
    }
    return map;
  }, [data]);

  return (
    <FieldHistoryContext.Provider value={{ byPath, isLoading }}>
      {children}
    </FieldHistoryContext.Provider>
  );
}

interface IconProps {
  fieldPath: string;
  className?: string;
}

/**
 * Renders nothing when the field has no history. When at least one
 * override row exists, renders a small clock button that opens a
 * popover with the diff timeline.
 */
export function FieldHistoryIcon({ fieldPath, className }: IconProps) {
  const { byPath } = useContext(FieldHistoryContext);
  const rows = byPath.get(fieldPath);
  if (!rows || rows.length === 0) return null;
  const meta = getBindableField(fieldPath);
  const label = meta?.label ?? fieldPath;

  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button
          variant="ghost"
          size="icon"
          className={cn('h-5 w-5 text-muted-foreground hover:text-foreground', className)}
          aria-label={`Field history for ${label}`}
          title={`${rows.length} override${rows.length === 1 ? '' : 's'}`}
        >
          <Clock className="h-3 w-3" aria-hidden />
        </Button>
      </PopoverTrigger>
      <PopoverContent align="start" className="w-80 p-0">
        <div className="border-b px-3 py-2">
          <div className="text-xs font-medium">{label}</div>
          <div className="text-xs text-muted-foreground">
            {rows.length} override{rows.length === 1 ? '' : 's'}
          </div>
        </div>
        <ScrollArea className="max-h-72">
          <ul className="divide-y text-xs">
            {rows.map((r) => (
              <li key={r.id} className="px-3 py-2 space-y-1">
                <div className="flex items-baseline justify-between gap-2">
                  <span className="font-medium">{formatSource(r.source)}</span>
                  <span className="text-xs text-muted-foreground">
                    {formatDistanceToNow(new Date(r.createdAt), { addSuffix: true })}
                  </span>
                </div>
                <div className="text-muted-foreground">
                  <span className="line-through">{formatValue(r.oldValue)}</span>
                  <span className="mx-1">→</span>
                  <span className="text-foreground">{formatValue(r.newValue)}</span>
                </div>
              </li>
            ))}
          </ul>
        </ScrollArea>
      </PopoverContent>
    </Popover>
  );
}

function formatValue(v: unknown): string {
  if (v === null || v === undefined) return '(empty)';
  if (typeof v === 'string') return v.length > 80 ? `${v.slice(0, 77)}…` : v;
  return JSON.stringify(v);
}

function formatSource(source: string): string {
  if (source === 'supplemental_form') return 'Supplemental info form';
  return source;
}
