import { useCallback, useEffect, useRef, useState } from "react";
import useImageScan from "./useImageScan";
import { useAppDispatch } from "../../useAppRedux";
import { updateUser } from "../../../store/slices/user";

export type Stage = "idle" | "analyzing" | "done";
export type Verdict = "synthetic" | "authentic" | "uncertain";

export type AnalysisResult = {
  genAIScore: number;
};

export type VerdictRule = {
  key: Verdict;
  label: string;
  colorClass: string;
  matches: (score: number) => boolean;
};

const SCAN_LINES = [
  "Reading sensor noise...",
  "Checking lens falloff...",
  "Cross-referencing diffusion signatures...",
  "Comparing known GAN artifacts...",
  "Auditing compression history...",
  "Filing the report...",
];

const VERDICT_RULES: VerdictRule[] = [
  {
    key: "synthetic",
    label: "Likely AI-generated",
    colorClass: "text-danger",
    matches: (score) => score >= 70,
  },
  {
    key: "authentic",
    label: "Camera-original",
    colorClass: "text-success",
    matches: (score) => score <= 20,
  },
  {
    key: "uncertain",
    label: "Inconclusive \u2014 mixed signals",
    colorClass: "text-amber-500",
    matches: () => true,
  },
];

function resolveVerdict(score: number): VerdictRule {
  return (
    VERDICT_RULES.find((rule) => rule.matches(score)) ??
    VERDICT_RULES[VERDICT_RULES.length - 1]
  );
}

function toPercentage(confidence: number): number {
  const pct = confidence <= 1 ? confidence * 100 : confidence;
  return Math.round(Math.min(100, Math.max(0, pct)));
}

function mapScanResponseToAnalysis(response: {
  aiGenerated: boolean;
  confidence: number;
  providerResponse: Record<string, any>;
}): AnalysisResult {
  const confidencePct = toPercentage(response.confidence);

  return {
    genAIScore: response.aiGenerated ? confidencePct : 0,
  };
}

export default function useDetectorPanel() {
  const [stage, setStage] = useState<Stage>("idle");
  const [dragging, setDragging] = useState(false);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [result, setResult] = useState<AnalysisResult | null>(null);
  const [scanLine, setScanLine] = useState(SCAN_LINES[0]);
  const [loadError, setLoadError] = useState<string | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const { scanImage } = useImageScan();

  const dispatch = useAppDispatch();

  useEffect(() => {
    if (stage !== "analyzing") return;
    let i = 0;
    const id = setInterval(() => {
      i = (i + 1) % SCAN_LINES.length;
      setScanLine(SCAN_LINES[i]);
    }, 420);
    return () => clearInterval(id);
  }, [stage]);

  const runAnalysis = useCallback(
    async (file: File) => {
      setLoadError(null);
      setResult(null);
      setPreviewUrl(URL.createObjectURL(file));
      setStage("analyzing");
      setScanLine(SCAN_LINES[0]);

      try {
        const formData = new FormData();
        formData.append("image", file);

        const response = await scanImage(formData);
        dispatch(
          updateUser({
            balance: response.creditsRemaining,
          }),
        );

        setResult(mapScanResponseToAnalysis(response));
        setStage("done");
      } catch {
        // useImageScan already shows an error toast on failure.
        setStage("idle");
      }
    },
    [scanImage],
  );

  const loadFromUrl = useCallback(
    async (url: string) => {
      try {
        setLoadError(null);
        const res = await fetch(url);
        const blob = await res.blob();
        const file = new File([blob], "exhibit.jpg", {
          type: blob.type || "image/jpeg",
        });
        runAnalysis(file);
      } catch {
        setLoadError(
          "Couldn't fetch that exhibit \u2014 try dropping a file instead.",
        );
      }
    },
    [runAnalysis],
  );

  const onDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      setDragging(false);
      const file = e.dataTransfer.files?.[0];
      if (file && file.type.startsWith("image/")) {
        runAnalysis(file);
        return;
      }
      const url =
        e.dataTransfer.getData("text/uri-list") ||
        e.dataTransfer.getData("text/plain");
      if (url) loadFromUrl(url);
    },
    [runAnalysis, loadFromUrl],
  );

  const onPick = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0];
      if (file) {
        runAnalysis(file);
      }
    },
    [runAnalysis],
  );

  const reset = useCallback(() => {
    setStage("idle");
    setResult(null);
    setPreviewUrl(null);
    setLoadError(null);
  }, []);

  const primaryScore = result?.genAIScore ?? 0;
  const verdict = resolveVerdict(primaryScore);

  return {
    stage,
    dragging,
    setDragging,
    previewUrl,
    result,
    scanLine,
    loadError,
    inputRef,
    onDrop,
    onPick,
    reset,
    primaryScore,
    verdict,
  };
}
