"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import {
  CheckCircle2,
  ChevronDown,
  ChevronUp,
  Loader2,
  RefreshCw,
  Satellite,
  FileText,
  TrendingUp,
  XCircle,
} from "lucide-react";
import type {
  ConditionalRequirement,
  FarmerExplanation,
  FinanceCaseStatus,
  ReasonCode,
  ScoringMeta,
  ScoringPhase,
  StepScoringData,
} from "@/lib/api-types";
import { getFarmerExplanationText } from "@/lib/scoring-reasons";
import { t, type WizardLocale } from "@/lib/i18n/wizard-labels";
import ShapFactorsChart from "@/components/scoring/ShapFactorsChart";

interface Props {
  data: Partial<StepScoringData>;
  loading: boolean;
  locale?: WizardLocale;
  onSave: (data: StepScoringData & Record<string, unknown>) => Promise<unknown>;
  onSaveDraft: (data: Partial<StepScoringData>) => Promise<unknown>;
  onPollStatus: () => Promise<Record<string, unknown> | null>;
}

type UiPhase = "geo" | "documents" | "scoring" | "done";
type ErrorKind = "failed" | "timeout" | null;

const PHASES: { key: UiPhase; icon: typeof Satellite; labelKey: string }[] = [
  { key: "geo", icon: Satellite, labelKey: "scoring.phaseGeo" },
  { key: "documents", icon: FileText, labelKey: "scoring.phaseDocuments" },
  { key: "scoring", icon: TrendingUp, labelKey: "scoring.phaseScoring" },
];

const MAX_POLLS = 20;
const POLL_INTERVAL = 3000;

function mapBackendPhase(scoringPhase?: string): UiPhase {
  if (!scoringPhase || scoringPhase === "geo") return "geo";
  if (scoringPhase === "documents") return "documents";
  if (scoringPhase === "scoring" || scoringPhase === "finalize") return "scoring";
  return "geo";
}

function extractExplanation(
  result: Record<string, unknown>,
): FarmerExplanation | undefined {
  const meta = result.scoringMeta as ScoringMeta | undefined;
  return (
    (result.farmerExplanation as FarmerExplanation | undefined) ??
    meta?.farmerExplanation
  );
}

function isScoringFinished(result: Record<string, unknown>): boolean {
  return Boolean(result.eligibilityOutcome) || result.status === "completed";
}

async function persistScoringResult(
  onSave: (data: StepScoringData & Record<string, unknown>) => Promise<unknown>,
  data: StepScoringData & Record<string, unknown>,
): Promise<void> {
  await onSave(data);
}

export default function StepScoring({ onSave, onPollStatus, locale = "uz" }: Props) {
  const [phase, setPhase] = useState<UiPhase>("geo");
  const [pollCount, setPollCount] = useState(0);
  const [topReasons, setTopReasons] = useState<ReasonCode[]>([]);
  const [satelliteImages, setSatelliteImages] = useState<string[]>([]);
  const [farmerExplanation, setFarmerExplanation] = useState<FarmerExplanation | undefined>();
  const [errorKind, setErrorKind] = useState<ErrorKind>(null);
  const [showExplanation, setShowExplanation] = useState(false);
  const [retryKey, setRetryKey] = useState(0);
  const onSaveRef = useRef(onSave);
  const onPollRef = useRef(onPollStatus);
  onSaveRef.current = onSave;
  onPollRef.current = onPollStatus;

  const runPoll = useCallback(async (cancelled: () => boolean) => {
    let attempts = 0;

    while (!cancelled() && attempts < MAX_POLLS) {
      await new Promise((r) => setTimeout(r, POLL_INTERVAL));
      if (cancelled()) return;

      attempts++;
      setPollCount(attempts);

      let result: Record<string, unknown> | null = null;
      try {
        result = await onPollRef.current();
      } catch {
        continue;
      }
      if (cancelled() || !result) continue;

      if (result.scoringPhase) {
        setPhase(mapBackendPhase(result.scoringPhase as ScoringPhase));
      }

      const images = result.satelliteImages as string[] | undefined;
      if (images?.length) setSatelliteImages(images);

      const explanation = extractExplanation(result);
      if (explanation) setFarmerExplanation(explanation);

      if (result.status === "failed") {
        setPhase("done");
        setErrorKind("failed");
        try {
          await persistScoringResult(onSaveRef.current, {
            scoringComplete: false,
            scoringError: true,
            scoringFailed: true,
            scoringTimeout: false,
            decision: undefined,
            score: undefined,
            reasonCodes: [],
          });
        } catch {
          // Best-effort persist for failed scoring
        }
        return;
      }

      if (isScoringFinished(result)) {
        const reasons = (result.reasonCodes as ReasonCode[] | undefined) ?? [];
        const meta = result.scoringMeta as ScoringMeta | undefined;
        setTopReasons(reasons.slice(0, 3));
        setPhase("done");
        setErrorKind(null);
        await persistScoringResult(onSaveRef.current, {
          scoringComplete: true,
          scoringError: false,
          scoringFailed: false,
          scoringTimeout: false,
          decision: (result.eligibilityOutcome as StepScoringData["decision"]) ?? "eligible",
          score: typeof result.score === "number" ? result.score : 750,
          reasonCodes: reasons,
          financeCaseId: result.financeCaseId as string | undefined,
          financeCaseStatus: result.financeCaseStatus as FinanceCaseStatus | undefined,
          conditionalRequirements: result.conditionalRequirements as
            | ConditionalRequirement[]
            | undefined,
          satelliteImages: images,
          farmerExplanation: explanation,
          scoringMeta: meta,
          satelliteSummary: meta?.satelliteSummary,
        });
        return;
      }
    }

    if (cancelled()) return;

    setPhase("done");
    setErrorKind("timeout");
    await persistScoringResult(onSaveRef.current, {
      scoringComplete: false,
      scoringError: true,
      scoringFailed: false,
      scoringTimeout: true,
      decision: undefined,
      score: undefined,
      reasonCodes: [],
    });
  }, []);

  useEffect(() => {
    let cancelled = false;
    const isCancelled = () => cancelled;

    setPhase("geo");
    setPollCount(0);
    setTopReasons([]);
    setSatelliteImages([]);
    setFarmerExplanation(undefined);
    setErrorKind(null);
    setShowExplanation(false);

    runPoll(isCancelled);
    return () => {
      cancelled = true;
    };
  }, [runPoll, retryKey]);

  const isProcessing = phase !== "done";
  const hasError = errorKind !== null;
  const explanationText = getFarmerExplanationText(farmerExplanation, locale);

  const handleRetry = () => {
    setRetryKey((k) => k + 1);
  };

  return (
    <div className="space-y-6 text-center py-8">
      <div className="flex justify-center">
        <div
          className={`w-16 h-16 rounded-full flex items-center justify-center ${
            hasError ? "bg-red-100" : "bg-green-deep/10"
          }`}
        >
          {isProcessing ? (
            <Loader2 className="w-8 h-8 text-green-deep animate-spin" />
          ) : hasError ? (
            <XCircle className="w-8 h-8 text-red-500" />
          ) : (
            <CheckCircle2 className="w-8 h-8 text-green-deep" />
          )}
        </div>
      </div>

      <div>
        <h2 className="font-onest text-2xl font-semibold text-ink">
          {hasError
            ? errorKind === "failed"
              ? t("scoring.failed", locale)
              : t("scoring.timeout", locale)
            : isProcessing
              ? t("scoring.processing", locale)
              : t("scoring.complete", locale)}
        </h2>
        <p className="mt-2 font-inter text-sm text-ink-soft max-w-sm mx-auto">
          {hasError
            ? errorKind === "failed"
              ? t("scoring.failedHint", locale)
              : t("scoring.timeoutHint", locale)
            : isProcessing
              ? t("scoring.processingHint", locale)
              : t("scoring.completeHint", locale)}
        </p>
      </div>

      {!hasError && (
        <div className="max-w-xs mx-auto space-y-2">
          {PHASES.map(({ key, icon: Icon, labelKey }) => {
            const phaseOrder: UiPhase[] = ["geo", "documents", "scoring"];
            const currentIdx = phase === "done" ? phaseOrder.length : phaseOrder.indexOf(phase);
            const itemIdx = phaseOrder.indexOf(key);
            const isDone = phase === "done" || itemIdx < currentIdx;
            const isActive = key === phase && phase !== "done";

            return (
              <div
                key={key}
                className={`flex items-center gap-3 px-4 py-2.5 rounded-xl transition-colors ${
                  isActive
                    ? "bg-green-deep/5 border border-green-deep/15"
                    : isDone
                      ? "bg-green-deep/3"
                      : "bg-green-deep/[0.02]"
                }`}
              >
                <div
                  className={`w-6 h-6 rounded-full flex items-center justify-center shrink-0 ${
                    isDone
                      ? "bg-green-deep text-white"
                      : isActive
                        ? "bg-green-deep/20 text-green-deep"
                        : "bg-surface-elevated text-muted/50"
                  }`}
                >
                  {isDone ? (
                    <CheckCircle2 className="w-3.5 h-3.5" />
                  ) : isActive ? (
                    <Loader2 className="w-3.5 h-3.5 animate-spin" />
                  ) : (
                    <Icon className="w-3.5 h-3.5" />
                  )}
                </div>
                <span
                  className={`font-inter text-sm ${
                    isDone
                      ? "text-green-deep font-medium"
                      : isActive
                        ? "text-ink-soft font-medium"
                        : "text-muted/70"
                  }`}
                >
                  {t(labelKey, locale)}
                </span>
              </div>
            );
          })}
        </div>
      )}

      {satelliteImages.length > 0 && (
        <div className="max-w-sm mx-auto text-left">
          <p className="font-inter text-xs font-medium text-muted uppercase tracking-wide text-center mb-2">
            {t("scoring.satellitePreview", locale)}
          </p>
          <div className="flex gap-2 justify-center">
            {satelliteImages.slice(0, 2).map((src, i) => (
              <div
                key={i}
                className="w-28 h-20 rounded-lg overflow-hidden border border-border bg-surface-elevated"
              >
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img
                  src={src}
                  alt={`${t("scoring.satellitePreview", locale)} ${i + 1}`}
                  className="w-full h-full object-cover"
                />
              </div>
            ))}
          </div>
        </div>
      )}

      {!isProcessing && !hasError && topReasons.length > 0 && (
        <div className="max-w-sm mx-auto text-left space-y-2">
          <p className="font-inter text-xs font-medium text-muted uppercase tracking-wide text-center">
            {t("scoring.keyFactors", locale)}
          </p>
          <ShapFactorsChart factors={topReasons} locale={locale} maxItems={3} />
        </div>
      )}

      {!isProcessing && !hasError && explanationText && (
        <div className="max-w-sm mx-auto text-left rounded-xl border border-border bg-surface p-4">
          <button
            type="button"
            onClick={() => setShowExplanation((v) => !v)}
            className="w-full flex items-center justify-between gap-2 cursor-pointer"
            aria-expanded={showExplanation}
          >
            <span className="font-inter text-sm font-medium text-ink">
              {t("scoring.explanationPreview", locale)}
            </span>
            {showExplanation ? (
              <ChevronUp className="w-4 h-4 text-muted shrink-0" />
            ) : (
              <ChevronDown className="w-4 h-4 text-muted shrink-0" />
            )}
          </button>
          {showExplanation && (
            <p className="mt-2 font-inter text-sm text-ink-soft leading-relaxed">
              {explanationText}
            </p>
          )}
          {!showExplanation && (
            <p className="mt-1 font-inter text-xs text-muted line-clamp-2">
              {explanationText}
            </p>
          )}
        </div>
      )}

      {hasError && (
        <button
          type="button"
          onClick={handleRetry}
          className="inline-flex items-center gap-2 px-5 py-2.5 rounded-full bg-green-deep text-white font-inter text-sm font-medium hover:bg-green-deep/90 transition-colors cursor-pointer"
        >
          <RefreshCw className="w-4 h-4" />
          {t("scoring.retry", locale)}
        </button>
      )}

      {isProcessing && (
        <div className="max-w-xs mx-auto">
          <div className="h-2 bg-surface-elevated rounded-full overflow-hidden">
            <div
              className="h-full bg-green-deep rounded-full transition-all duration-500"
              style={{ width: `${Math.min((pollCount / MAX_POLLS) * 100, 95)}%` }}
            />
          </div>
        </div>
      )}
    </div>
  );
}
