'use client';

import { useEffect, useState } from 'react';
import { useParams } from 'next/navigation';
import { useQuery } from '@tanstack/react-query';
import { AlertCircle, Archive, ArrowRight, Briefcase, X } from 'lucide-react';
import Link from 'next/link';

import { Button } from '@/components/ui/button';
import { apiFetch } from '@/lib/api/client';
import { cn } from '@/lib/utils';

interface MatchData {
  clientId: string;
  fullName: string;
  score: number;
  confidence: 'high' | 'medium' | 'low';
  reasons: string[];
  interestCount: number;
  emails: string[];
  phonesE164: string[];
  /** ISO timestamp when the client was archived. When set, the matched
   *  client is soft-deleted - the suggestion panel surfaces a Restore link
   *  to the existing restore wizard instead of "Use this client". */
  archivedAt: string | null;
}

interface DedupSuggestionPanelProps {
  /** Free-text inputs from the in-flight new-client form. The panel
   *  debounces them and queries /api/v1/clients/match-candidates. */
  email?: string | null;
  phone?: string | null;
  name?: string | null;
  /** Caller wants to attach the new interest to an existing client
   *  rather than creating a new one. The form switches to
   *  interest-only mode and pre-fills the client. */
  onUseExisting: (match: MatchData) => void;
  /** User explicitly said "create new anyway." Hide the panel until
   *  they change input again. */
  onDismiss?: () => void;
}

/**
 * Surfaces existing clients that match the form's in-flight inputs.
 *
 * Renders nothing while inputs are short / no useful match found.
 * On a high-confidence match, the panel interrupts visually with a
 * solid border and a primary "Use this client" button.
 *
 * Wired into the new-client form. Skipped in edit mode.
 */
export function DedupSuggestionPanel({
  email,
  phone,
  name,
  onUseExisting,
  onDismiss,
}: DedupSuggestionPanelProps) {
  const params = useParams<{ portSlug: string }>();
  const portSlug = params?.portSlug ?? '';
  const [dismissed, setDismissed] = useState(false);

  // Debounce inputs by 300ms so we don't fire on every keystroke. Keep
  // the latest debounced values in component state.
  const [debounced, setDebounced] = useState({
    email: email ?? '',
    phone: phone ?? '',
    name: name ?? '',
  });

  useEffect(() => {
    const t = setTimeout(() => {
      setDebounced({ email: email ?? '', phone: phone ?? '', name: name ?? '' });
      // Clear the dismissed flag when inputs change - the user typed
      // something new, so the prior dismissal no longer applies.
      setDismissed(false);
    }, 300);
    return () => clearTimeout(t);
  }, [email, phone, name]);

  const hasSomething =
    debounced.email.length > 3 || debounced.phone.length > 3 || debounced.name.length > 2;

  const { data, isFetching } = useQuery<{ data: MatchData[] }>({
    queryKey: ['dedup-match-candidates', debounced],
    queryFn: () => {
      const params = new URLSearchParams();
      if (debounced.email) params.set('email', debounced.email);
      if (debounced.phone) params.set('phone', debounced.phone);
      if (debounced.name) params.set('name', debounced.name);
      return apiFetch<{ data: MatchData[] }>(`/api/v1/clients/match-candidates?${params}`);
    },
    enabled: hasSomething && !dismissed,
    // Same query is fine to cache for a minute - moves are slow at this layer.
    staleTime: 60_000,
  });

  if (dismissed) return null;
  if (!hasSomething) return null;
  if (isFetching && !data) return null;
  const matches = data?.data ?? [];
  if (matches.length === 0) return null;

  const top = matches[0]!;
  const isHigh = top.confidence === 'high';
  const isArchived = !!top.archivedAt;

  return (
    <div
      className={cn(
        'rounded-lg border p-3 mb-3 transition-colors',
        isArchived
          ? 'border-slate-300 bg-slate-50/60 dark:border-slate-700 dark:bg-slate-900/40'
          : isHigh
            ? 'border-amber-300 bg-amber-50/60 dark:bg-amber-950/30'
            : 'border-border bg-muted/40',
      )}
      data-testid="dedup-suggestion"
    >
      <div className="flex items-start gap-3">
        <div className="mt-0.5">
          {isArchived ? (
            <Archive className="size-5 text-slate-600 dark:text-slate-400" aria-hidden />
          ) : (
            <AlertCircle
              className={cn(
                'size-5',
                isHigh ? 'text-amber-700 dark:text-amber-400' : 'text-muted-foreground',
              )}
              aria-hidden
            />
          )}
        </div>
        <div className="min-w-0 flex-1">
          <p className="text-sm font-semibold leading-tight">
            {isArchived
              ? 'This contact info belongs to an archived client'
              : isHigh
                ? 'This looks like an existing client'
                : 'Possible match - check before creating'}
          </p>
          {isArchived && (
            <p className="mt-0.5 text-xs text-muted-foreground">
              Restore the existing record (keeping its history + interests), or create a fresh one
              if this is a different person.
            </p>
          )}
          <div className="mt-2 rounded-md border bg-background/80 p-2.5">
            <div className="flex items-center gap-2">
              <p className="truncate text-sm font-medium">{top.fullName}</p>
              {isArchived && (
                <span className="shrink-0 rounded-full bg-slate-200 px-1.5 py-0.5 text-xs font-medium uppercase tracking-wide text-slate-800 dark:bg-slate-700 dark:text-slate-200">
                  archived
                </span>
              )}
              <span
                className={cn(
                  'shrink-0 rounded-full px-1.5 py-0.5 text-xs font-medium uppercase tracking-wide',
                  isHigh
                    ? 'bg-amber-200 text-amber-900 dark:bg-amber-800 dark:text-amber-100'
                    : 'bg-muted text-muted-foreground',
                )}
              >
                {top.confidence}
              </span>
            </div>
            <div className="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground">
              {top.emails[0] ? <span className="truncate">{top.emails[0]}</span> : null}
              {top.phonesE164[0] ? <span>{top.phonesE164[0]}</span> : null}
              <span className="inline-flex items-center gap-1">
                <Briefcase className="size-3" aria-hidden />
                {top.interestCount} {top.interestCount === 1 ? 'interest' : 'interests'}
              </span>
              {isArchived && top.archivedAt && (
                <span className="inline-flex items-center gap-1">
                  archived {new Date(top.archivedAt).toLocaleDateString()}
                </span>
              )}
            </div>
            <p className="mt-1.5 text-xs text-muted-foreground">{top.reasons.join(' · ')}</p>
          </div>
          <div className="mt-3 flex flex-wrap items-center gap-2">
            {isArchived ? (
              <Button asChild type="button" size="sm">
                <Link
                  href={`/${portSlug}/clients/${top.clientId}/restore`}
                  data-testid="dedup-restore-archived"
                >
                  Restore this client
                  <ArrowRight className="ml-1 size-3.5" aria-hidden />
                </Link>
              </Button>
            ) : (
              <Button
                type="button"
                size="sm"
                onClick={() => onUseExisting(top)}
                data-testid="dedup-use-existing"
              >
                Use this client
                <ArrowRight className="ml-1 size-3.5" aria-hidden />
              </Button>
            )}
            <Button
              type="button"
              size="sm"
              variant="ghost"
              onClick={() => {
                setDismissed(true);
                onDismiss?.();
              }}
              data-testid="dedup-dismiss"
            >
              <X className="mr-1 size-3.5" aria-hidden />
              {isArchived ? 'Create new anyway (different person)' : 'Create new anyway'}
            </Button>
            {matches.length > 1 ? (
              <span className="text-xs text-muted-foreground">
                +{matches.length - 1} other possible{' '}
                {matches.length - 1 === 1 ? 'match' : 'matches'}
              </span>
            ) : null}
          </div>
        </div>
      </div>
    </div>
  );
}
