'use client';

import type { QueryClient } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { useRef } from 'react';
import { qk } from '@/lib/query/keys';
import { getBrowserQueryClient } from '@/lib/query/client';
import {
  ADMIN_SUPPORT_PREFETCH_DESCRIPTORS,
  adminSupportKeys,
} from '@/features/admin-support/internals/useAdminSupport';
import { ADMIN_VENDOR_APPROVAL_PREFETCH_DESCRIPTOR } from '@/features/admin-approval/ApprovalInbox';
import { VENDOR_DASHBOARD_PREFETCH_DESCRIPTOR } from '@/features/vendor-dashboard/useVendorDashboardData';
import { VENDOR_DEALS_PREFETCH_DESCRIPTOR } from '@/features/vendor-deals/VendorDeals';
import { VENDOR_ANALYTICS_PREFETCH_DESCRIPTOR } from '@/features/vendor-analytics/VendorAnalytics';
import { VENDOR_CUSTOMERS_PREFETCH_DESCRIPTOR } from '@/features/vendor-customers/VendorCustomers';
import { VENDOR_PROMO_CODES_PREFETCH_DESCRIPTOR } from '@/features/vendor-promo-codes/PromoCodesList';

type PrefetchRunner = (qc: QueryClient) => Promise<unknown>;

export interface DashboardPrefetchDescriptor {
  href: string;
  queryKey: readonly unknown[];
  queryFn: () => Promise<unknown>;
  staleTime?: number;
  gcTime?: number;
}

export const PREFETCH_DESCRIPTOR_EXCEPTIONS = [
  {
    href: '/admin',
    reason:
      'Uses Analytics client-side fetch state instead of a shared React Query descriptor; top-level overview still needs query-owner migration before descriptor prefetch can warm the rendered state.',
  },
  {
    href: '/admin/vendors',
    reason:
      'SSR-only overview page. It renders server-loaded stats and has no client query or loading gate to bind to a descriptor.',
  },
  {
    href: '/admin/deals',
    reason:
      'SSR-only overview page. It renders server-loaded stats and has no client query or loading gate to bind to a descriptor.',
  },
  {
    href: '/admin/purchases/orders',
    reason:
      'Still uses usePaginatedQuery instead of React Query descriptors, so nav prefetch cannot warm the page state yet.',
  },
] as const;

async function fetchJson<T = unknown>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) throw new Error(`prefetch failed: ${url}`);
  return res.json() as Promise<T>;
}

async function prefetchRouteOnce(qc: QueryClient, href: string, seen: Set<string>): Promise<void> {
  const runner = PREFETCH_REGISTRY[href];
  if (!runner || seen.has(href)) return;
  seen.add(href);
  try {
    await runner(qc);
  } catch (error) {
    seen.delete(href);
    throw error;
  }
}

function createPrefetchRunner(descriptor: DashboardPrefetchDescriptor): PrefetchRunner {
  return (qc) =>
    qc.prefetchQuery({
      queryKey: descriptor.queryKey,
      queryFn: descriptor.queryFn,
      staleTime: descriptor.staleTime,
      gcTime: descriptor.gcTime,
    });
}

function buildPrefetchRegistry(
  descriptors: readonly DashboardPrefetchDescriptor[],
): Record<string, PrefetchRunner> {
  return Object.fromEntries(
    descriptors.map((descriptor) => [descriptor.href, createPrefetchRunner(descriptor)]),
  );
}

const legacyVendorProfileQuery = () =>
  fetchJson<{ vendor: unknown }>('/api/vendor/profile').then((json) => json.vendor);

export const LEGACY_PREFETCH_REGISTRY: Record<string, PrefetchRunner> = {
  '/vendor/messages': (qc) =>
    qc.prefetchQuery({
      queryKey: ['vendor-purchase-messages'],
      queryFn: () => fetchJson('/api/vendor/purchase-messages'),
    }),
  '/vendor/profile': (qc) =>
    qc.prefetchQuery({
      queryKey: qk.vendorProfile(),
      queryFn: legacyVendorProfileQuery,
      staleTime: 60_000,
    }),
  '/vendor/settings': (qc) =>
    qc.prefetchQuery({
      queryKey: qk.vendorProfile(),
      queryFn: legacyVendorProfileQuery,
      staleTime: 60_000,
    }),
  '/vendor/settings/payments': (qc) =>
    qc.prefetchQuery({
      queryKey: qk.vendorProfile(),
      queryFn: legacyVendorProfileQuery,
      staleTime: 60_000,
    }),
  '/vendor/settings/notifications': (qc) =>
    qc.prefetchQuery({
      queryKey: ['vendor-notif-prefs'],
      queryFn: () =>
        fetchJson<{ prefs: unknown }>('/api/vendor/notifications/settings').then(
          (json) => json.prefs,
        ),
      staleTime: 60_000,
    }),
  '/vendor/settings/invoicing': (qc) =>
    qc.prefetchQuery({
      queryKey: qk.vendorProfile(),
      queryFn: legacyVendorProfileQuery,
      staleTime: 60_000,
    }),
  '/vendor/returns': (qc) =>
    qc.prefetchQuery({
      queryKey: qk.cases('vendor'),
      queryFn: () =>
        fetchJson<{ cases?: unknown[] }>('/api/cases?role=vendor').then((json) => json.cases ?? []),
    }),
  '/admin/support': (qc) =>
    qc.prefetchQuery({
      queryKey: adminSupportKeys.inbox({
        type: 'all',
        slaBreach: 'any',
        assigned: 'any',
        page: 1,
        pageSize: 25,
        sort: 'sla_soonest',
      }),
      queryFn: () =>
        fetchJson(
          '/api/admin/support/inbox?type=all&slaBreach=any&assigned=any&page=1&pageSize=25&sort=sla_soonest',
        ),
    }),
  '/admin/support/kb': (qc) =>
    qc.prefetchQuery({
      queryKey: adminSupportKeys.kbList({}),
      queryFn: () => fetchJson('/api/admin/support/kb'),
    }),
  '/admin/support/config': (qc) =>
    qc.prefetchQuery({
      queryKey: adminSupportKeys.settings(),
      queryFn: () => fetchJson('/api/admin/moderation/support-settings'),
    }),
  '/admin/support/metrics': (qc) =>
    qc.prefetchQuery({
      queryKey: adminSupportKeys.metrics({ from: '', to: '' }),
      queryFn: () => fetchJson('/api/admin/support/metrics'),
    }),
  '/admin/support/definitions': (qc) =>
    qc.prefetchQuery({
      queryKey: adminSupportKeys.definitions(),
      queryFn: () => fetchJson('/api/admin/support/definitions'),
    }),
};

export const DASHBOARD_PREFETCH_DESCRIPTORS: readonly DashboardPrefetchDescriptor[] = [
  ...ADMIN_SUPPORT_PREFETCH_DESCRIPTORS,
  ADMIN_VENDOR_APPROVAL_PREFETCH_DESCRIPTOR,
  VENDOR_DASHBOARD_PREFETCH_DESCRIPTOR,
  VENDOR_DEALS_PREFETCH_DESCRIPTOR,
  VENDOR_ANALYTICS_PREFETCH_DESCRIPTOR,
  VENDOR_CUSTOMERS_PREFETCH_DESCRIPTOR,
  VENDOR_PROMO_CODES_PREFETCH_DESCRIPTOR,
];

export const DESCRIPTOR_PREFETCH_REGISTRY = buildPrefetchRegistry(DASHBOARD_PREFETCH_DESCRIPTORS);

export const PREFETCH_REGISTRY: Record<string, PrefetchRunner> = {
  ...LEGACY_PREFETCH_REGISTRY,
  ...DESCRIPTOR_PREFETCH_REGISTRY,
};

export function usePrefetchOnIntent() {
  const qc = useQueryClient();
  const seenRef = useRef(new Set<string>());

  return (href: string) => ({
    onMouseEnter: () => {
      void prefetchRouteOnce(qc, href, seenRef.current);
    },
    onFocus: () => {
      void prefetchRouteOnce(qc, href, seenRef.current);
    },
  });
}

interface PrefetchQueryRoot {
  querySelectorAll<T extends Element = Element>(selector: string): NodeListOf<T>;
}

export function installPrefetchOnIntent(selector: string, root: PrefetchQueryRoot = document) {
  const qc = getBrowserQueryClient();
  const seen = new Set<string>();

  for (const node of root.querySelectorAll<HTMLAnchorElement>(selector)) {
    const href = node.getAttribute('href');
    if (!href || !PREFETCH_REGISTRY[href] || node.dataset.queryPrefetchBound === 'true') continue;

    const run = () => {
      void prefetchRouteOnce(qc, href, seen);
    };

    node.dataset.queryPrefetchBound = 'true';
    node.addEventListener('mouseenter', run, { passive: true });
    node.addEventListener('focus', run);
  }
}
