'use client';

import { keepPreviousData, useQuery } from '@tanstack/react-query';

import { apiFetch } from '@/lib/api/client';
import { useDebounce } from '@/hooks/use-debounce';

// ─── Types - mirror SearchResults from search.service.ts ─────────────────────

export type BucketType =
  | 'clients'
  | 'residentialClients'
  | 'yachts'
  | 'companies'
  | 'interests'
  | 'residentialInterests'
  | 'berths'
  | 'invoices'
  | 'expenses'
  | 'documents'
  | 'files'
  | 'reminders'
  | 'brochures'
  | 'tags'
  | 'navigation'
  | 'notes'
  | 'stages';

/**
 * Provenance hint for a result row that surfaced via graph expansion
 * rather than a direct match against the query. Rendered as a "via X"
 * subtitle by the result-row UI.
 */
export interface RelatedVia {
  type: 'berth' | 'interest' | 'client' | 'yacht' | 'company';
  id: string;
  label: string;
}

export interface ClientResult {
  id: string;
  fullName: string;
  matchedContact: string | null;
  matchedContactChannel: 'email' | 'phone' | 'whatsapp' | null;
  archivedAt: string | null;
  relatedVia?: RelatedVia | null;
  matchedOn?: string | null;
}
export interface ResidentialClientResult {
  id: string;
  fullName: string;
  email: string | null;
  phone: string | null;
  status: string;
  archivedAt: string | null;
}
export interface YachtResult {
  id: string;
  name: string;
  hullNumber: string | null;
  registration: string | null;
  archivedAt: string | null;
  relatedVia?: RelatedVia | null;
}
export interface CompanyResult {
  id: string;
  name: string;
  legalName: string | null;
  taxId: string | null;
  matchedField: 'name' | 'legalName' | 'taxId' | 'billingEmail' | 'registrationNumber' | null;
  archivedAt: string | null;
  relatedVia?: RelatedVia | null;
}
export interface InterestResult {
  id: string;
  clientName: string;
  berthMooringNumber: string | null;
  pipelineStage: string;
  outcome: string | null;
  relatedVia?: RelatedVia | null;
}
export interface ResidentialInterestResult {
  id: string;
  clientName: string;
  pipelineStage: string;
}
export interface BerthResult {
  id: string;
  mooringNumber: string;
  area: string | null;
  status: string;
  linkedInterestCount: number;
  relatedVia?: RelatedVia | null;
}
export interface InvoiceResult {
  id: string;
  invoiceNumber: string;
  clientName: string;
  status: string;
  paymentStatus: string | null;
  totalAmount: string | null;
  currency: string;
}
export interface ExpenseResult {
  id: string;
  description: string | null;
  vendor: string | null;
  tripLabel: string | null;
  amount: string;
  currency: string;
  paymentStatus: string | null;
}
export interface DocumentResult {
  id: string;
  title: string;
  documentType: string;
  status: string;
  matchedSignerName: string | null;
}
export interface FileResult {
  id: string;
  filename: string;
  category: string | null;
  ownerLabel: string | null;
}
export interface ReminderResult {
  id: string;
  title: string;
  dueAt: string;
  priority: string;
  status: string;
}
export interface BrochureResult {
  id: string;
  label: string;
  isDefault: boolean;
  archivedAt: string | null;
}
export interface TagResult {
  id: string;
  name: string;
  color: string;
  totalCount: number;
}
export interface NavResult {
  id: string;
  href: string;
  label: string;
  category: 'settings' | 'admin' | 'dashboard';
}
export interface StageSuggestionResult {
  /** Canonical pipeline-stage value (matches PIPELINE_STAGES). */
  stage: string;
  /** Human label (STAGE_LABELS[stage]). */
  label: string;
  /** Live count of non-archived interests in this stage. */
  count: number;
  /** Slug-less href. CommandSearch prefixes the portSlug at render time. */
  href: string;
}
export interface OtherPortResult {
  portId: string;
  portSlug: string;
  portName: string;
  type: 'client' | 'yacht' | 'company' | 'berth' | 'interest';
  id: string;
  label: string;
  sub: string | null;
}

export interface SearchResults {
  clients: ClientResult[];
  residentialClients: ResidentialClientResult[];
  yachts: YachtResult[];
  companies: CompanyResult[];
  interests: InterestResult[];
  residentialInterests: ResidentialInterestResult[];
  berths: BerthResult[];
  invoices: InvoiceResult[];
  expenses: ExpenseResult[];
  documents: DocumentResult[];
  files: FileResult[];
  reminders: ReminderResult[];
  brochures: BrochureResult[];
  tags: TagResult[];
  navigation: NavResult[];
  notes: NoteResult[];
  stages: StageSuggestionResult[];
  totals: Record<BucketType, number>;
  otherPorts?: OtherPortResult[];
}

export interface NoteResult {
  id: string;
  snippet: string;
  source: 'client' | 'interest' | 'yacht' | 'company';
  sourceId: string;
  sourceLabel: string;
  createdAt: string;
}

export interface RecentlyViewedItem {
  type: string;
  id: string;
  label: string;
  sub: string | null;
  href: string;
  viewedAt: number;
}

// ─── Hooks ────────────────────────────────────────────────────────────────────

export interface UseSearchOptions {
  /** When set, narrows the result set to a single bucket. */
  type?: BucketType;
  /** Per-bucket cap. Default 5 (dropdown); use 25 for the /search page. */
  limit?: number;
  /** Super-admin opt-in for cross-port matches. Silently ignored otherwise. */
  includeOtherPorts?: boolean;
  /** Override the 300ms input debounce. */
  debounceMs?: number;
}

export function useSearch(query: string, opts: UseSearchOptions = {}) {
  const debouncedQuery = useDebounce(query, opts.debounceMs ?? 300);
  const enabled = debouncedQuery.length >= 2;

  const params = new URLSearchParams();
  params.set('q', debouncedQuery);
  if (opts.type) params.set('type', opts.type);
  if (opts.limit) params.set('limit', String(opts.limit));
  if (opts.includeOtherPorts) params.set('includeOtherPorts', 'true');

  const searchQuery = useQuery<SearchResults>({
    queryKey: [
      'search',
      debouncedQuery,
      opts.type ?? 'all',
      opts.limit ?? 5,
      opts.includeOtherPorts ?? false,
    ],
    queryFn: ({ signal }) =>
      apiFetch<SearchResults>(`/api/v1/search?${params.toString()}`, { signal }),
    enabled,
    // Keep previous results visible while the next debounced query loads
    // - eliminates the dropdown flicker when the user is typing fast.
    placeholderData: keepPreviousData,
    staleTime: 30_000,
  });

  const recentSearchQuery = useQuery<{ searches: string[] }>({
    queryKey: ['search', 'recent-terms'],
    queryFn: ({ signal }) => apiFetch<{ searches: string[] }>('/api/v1/search/recent', { signal }),
    staleTime: 60_000,
  });

  const recentlyViewedQuery = useQuery<{ data: RecentlyViewedItem[] }>({
    queryKey: ['search', 'recently-viewed'],
    queryFn: ({ signal }) =>
      apiFetch<{ data: RecentlyViewedItem[] }>('/api/v1/search/recently-viewed', { signal }),
    staleTime: 30_000,
  });

  return {
    results: searchQuery.data,
    isLoading: searchQuery.isLoading,
    isFetching: searchQuery.isFetching,
    enabled,
    recentSearches: recentSearchQuery.data?.searches ?? [],
    recentlyViewed: recentlyViewedQuery.data?.data ?? [],
  };
}

/**
 * Track that the current user just opened an entity. Call once on mount
 * from each entity detail page (via `useTrackEntityView`); the resulting
 * (type, id) pair is used by the search dropdown's "Recently viewed"
 * section to surface the user's working set.
 */
export async function trackEntityView(type: string, id: string): Promise<void> {
  try {
    await apiFetch('/api/v1/search/recently-viewed', {
      method: 'POST',
      body: { type, id },
    });
  } catch {
    // Tracking is non-critical - never bubble up to the user.
  }
}
