"use client";

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { siteKeys } from "./keys";

// --- Types ---

export interface SiteWithLatest {
  id: string;
  organizationId: string;
  createdByUserId: string | null;
  hostname: string;
  url: string;
  label: string | null;
  createdAt: string;
  latestTest: CachedTest | null;
  sparkline: { performanceScore: number | null; createdAt: string }[];
}

export interface CachedTest {
  id: string;
  siteId: string | null;
  status: string;
  lcp: number | null;
  tbt: number | null;
  cls: number | null;
  fcp: number | null;
  ttfb: number | null;
  fid: number | null;
  si: number | null;
  fullyLoaded: number | null;
  requests: number | null;
  transferSize: number | null;
  performanceScore: number | null;
  createdAt: string;
  completedAt: string | null;
  reportUrl: string | null;
  screenshotAfter: string | null;
  screenshotLcp: string | null;
  screenshotCls: string | null;
  [key: string]: unknown;
}

export interface SiteDetail {
  id: string;
  hostname: string;
  url: string;
  label: string | null;
  createdAt: string;
  tests: CachedTest[];
}

// --- Hooks ---

export function useSitesQuery() {
  return useQuery<SiteWithLatest[]>({
    queryKey: siteKeys.list(),
    queryFn: async () => {
      const res = await fetch("/api/sites");
      if (!res.ok) throw new Error("Failed to fetch sites");
      return res.json();
    },
  });
}

export function useSiteDetailQuery(siteId: string) {
  return useQuery<SiteDetail>({
    queryKey: siteKeys.detail(siteId),
    queryFn: async () => {
      const res = await fetch(`/api/sites/${siteId}`);
      if (!res.ok) throw new Error("Failed to fetch site");
      return res.json();
    },
  });
}

export function useAddSiteMutation() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async (url: string) => {
      const res = await fetch("/api/sites", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ url }),
      });
      if (!res.ok) {
        const d = await res.json().catch(() => ({}));
        throw new Error(d.error || "Failed");
      }
      return res.json();
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: siteKeys.list() }),
  });
}

export function useLaunchTestMutation(siteId: string) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async (device: "desktop" | "mobile" = "desktop") => {
      const res = await fetch(`/api/sites/${siteId}/test`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ device }),
      });
      if (!res.ok) {
        const d = await res.json().catch(() => ({}));
        throw new Error(d.error || "Failed");
      }
      return res.json() as Promise<{ id: string; status: string; siteId: string }>;
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: siteKeys.detail(siteId) });
      qc.invalidateQueries({ queryKey: siteKeys.list() });
    },
  });
}

export interface TestPollResult {
  status: "queued" | "running" | "completed" | "failed";
  error?: string | null;
  // Live queue context — only present while status === "queued".
  queuePosition?: number;
  queueLength?: number;
  estimatedWaitMs?: number;
}

export function useSiteTestPoll(siteId: string, testId: string | null) {
  return useQuery<TestPollResult>({
    queryKey: siteKeys.test(siteId, testId ?? ""),
    queryFn: async (): Promise<TestPollResult> => {
      const res = await fetch(`/api/sites/${siteId}/test?testId=${testId}`);
      if (!res.ok) {
        // API returned 404 — test lost (server restart). Return failed so polling stops.
        return { status: "failed", error: `API returned ${res.status}` };
      }
      return (await res.json()) as TestPollResult;
    },
    enabled: !!testId,
    retry: false,
    refetchInterval: (query) => {
      // Stop polling on terminal states or errors
      if (query.state.error) return false;
      const status = query.state.data?.status;
      if (status === "completed" || status === "failed") return false;
      // Queued users want fresher position updates; running can stay slow.
      return status === "queued" ? 2500 : 5000;
    },
  });
}
