import { useCallback, useEffect, useRef, useState } from "react";
import { useNavigate, useSearchParams, useLocation } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Skeleton } from "@/components/ui/skeleton";
import { Progress } from "@/components/ui/progress";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Mic, Loader2, Square } from "lucide-react";
import { placementService } from "@/services/placement.service";
import { usePlacementAnswer, usePlacementAutoSave } from "@/hooks/queries/usePlacement";
import type { CATQuestion, CATSection } from "@/types";
import { cn } from "@/lib/utils";

type LocationState = { question?: CATQuestion; sessionId?: string };

function sectionTitle(s: CATSection): string {
  return s.charAt(0).toUpperCase() + s.slice(1);
}

export default function PlacementTest() {
  const [searchParams] = useSearchParams();
  const sessionId = searchParams.get("session") || "";
  const navigate = useNavigate();
  const location = useLocation();
  const locState = location.state as LocationState | undefined;

  const answerMut = usePlacementAnswer();
  const autoSave = usePlacementAutoSave();

  const [question, setQuestion] = useState<CATQuestion | null>(null);
  const [initializing, setInitializing] = useState(true);
  const [betweenQuestions, setBetweenQuestions] = useState(false);
  const [progressInfo, setProgressInfo] = useState<{ current: number; estimated_total: number } | null>(null);
  const [sectionBridge, setSectionBridge] = useState<{
    from: CATSection;
    to: CATSection;
    nextQuestion: CATQuestion;
  } | null>(null);

  const [singleAnswer, setSingleAnswer] = useState("");
  const [multiAnswer, setMultiAnswer] = useState<string[]>([]);
  const questionStartedAt = useRef<number>(Date.now());
  const draftRef = useRef<{ question_id: number; answer: string | string[] } | null>(null);

  useEffect(() => {
    if (!sessionId) {
      navigate("/student/placement", { replace: true });
      return;
    }
    const fromState = locState?.question;
    const fromStorage = sessionStorage.getItem(`placement_session_${sessionId}`);
    let parsed: CATQuestion | null = null;
    if (fromStorage) {
      try {
        const j = JSON.parse(fromStorage) as { question?: CATQuestion };
        parsed = j.question ?? null;
      } catch {
        parsed = null;
      }
    }
    const q = fromState ?? parsed;
    if (q) {
      setQuestion(q);
      questionStartedAt.current = Date.now();
    }
    setInitializing(false);
  }, [sessionId, navigate, locState]);

  useEffect(() => {
    if (!question) return;
    setSingleAnswer("");
    setMultiAnswer([]);
    questionStartedAt.current = Date.now();
  }, [question?.id]);

  useEffect(() => {
    if (!question) return;
    const id = question.id;
    if (question.type === "mcq_multi") {
      draftRef.current = { question_id: id, answer: multiAnswer };
    } else {
      draftRef.current = { question_id: id, answer: singleAnswer };
    }
  }, [question, singleAnswer, multiAnswer]);

  useEffect(() => {
    if (!sessionId || !draftRef.current) return;
    const tick = window.setInterval(() => {
      const d = draftRef.current;
      if (!d) return;
      void autoSave.mutate({ session_id: sessionId, current_answer: d });
    }, 10000);
    return () => window.clearInterval(tick);
  }, [sessionId, autoSave]);

  const elapsedRef = useRef(0);
  const [, setTick] = useState(0);
  useEffect(() => {
    const t = window.setInterval(() => {
      elapsedRef.current += 1;
      setTick((x) => x + 1);
    }, 1000);
    return () => window.clearInterval(t);
  }, []);

  const formatElapsed = (sec: number) => {
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}:${s.toString().padStart(2, "0")}`;
  };

  const buildAnswerPayload = (): string | string[] => {
    if (!question) return "";
    if (question.type === "mcq_multi") return multiAnswer;
    if (question.type === "gap_fill") return singleAnswer.trim();
    return singleAnswer;
  };

  const submit = async () => {
    if (!question || !sessionId) return;
    const timeSpent = Date.now() - questionStartedAt.current;
    setBetweenQuestions(true);
    try {
      const res = await answerMut.mutateAsync({
        session_id: sessionId,
        question_id: question.id,
        answer: buildAnswerPayload(),
        time_spent_ms: timeSpent,
      });
      if (res.progress) setProgressInfo(res.progress);
      if (res.test_complete) {
        navigate(`/student/placement/results?session=${encodeURIComponent(sessionId)}`);
        return;
      }
      if (res.section_complete && res.next_question) {
        setSectionBridge({
          from: question.section,
          to: res.next_question.section,
          nextQuestion: res.next_question,
        });
        return;
      }
      if (res.next_question) {
        setQuestion(res.next_question);
        sessionStorage.setItem(`placement_session_${sessionId}`, JSON.stringify({ question: res.next_question }));
      }
    } finally {
      setBetweenQuestions(false);
    }
  };

  const continueAfterSection = () => {
    if (!sectionBridge || !sessionId) return;
    setQuestion(sectionBridge.nextQuestion);
    sessionStorage.setItem(
      `placement_session_${sessionId}`,
      JSON.stringify({ question: sectionBridge.nextQuestion }),
    );
    setSectionBridge(null);
  };

  const toggleMulti = (label: string) => {
    setMultiAnswer((prev) => (prev.includes(label) ? prev.filter((x) => x !== label) : [...prev, label]));
  };

  const displayProgress = progressInfo ?? {
    current: question?.estimated_total ? 1 : 0,
    estimated_total: question?.estimated_total ?? 0,
  };

  const approxFinal =
    displayProgress.estimated_total > 0 && displayProgress.current >= displayProgress.estimated_total;

  if (!sessionId) return null;

  if (!initializing && !question && !sectionBridge) {
    return (
      <div className="min-h-screen flex items-center justify-center p-6 bg-background">
        <Card className="max-w-md w-full border-0 shadow-lg">
          <CardHeader>
            <CardTitle>Session unavailable</CardTitle>
            <CardDescription>Return to the briefing and start the test again.</CardDescription>
          </CardHeader>
          <CardContent>
            <Button onClick={() => navigate("/student/placement")}>Back</Button>
          </CardContent>
        </Card>
      </div>
    );
  }

  if (sectionBridge) {
    return (
      <div className="min-h-screen flex flex-col bg-background">
        <header className="border-b px-6 py-4 flex items-center justify-between bg-card/80 backdrop-blur">
          <span className="text-sm font-medium text-muted-foreground">Section complete</span>
          <span className="text-sm tabular-nums">{formatElapsed(elapsedRef.current)}</span>
        </header>
        <main className="flex-1 flex items-center justify-center p-6">
          <Card className="max-w-lg w-full border-0 shadow-xl text-center">
            <CardHeader>
              <CardTitle>
                {sectionTitle(sectionBridge.from)} complete. Next: {sectionTitle(sectionBridge.to)}
              </CardTitle>
              <CardDescription>Take a short breath — continue when you&apos;re ready.</CardDescription>
            </CardHeader>
            <CardContent>
              <Button size="lg" className="w-full" onClick={continueAfterSection}>
                Continue
              </Button>
            </CardContent>
          </Card>
        </main>
      </div>
    );
  }

  return (
    <div className="min-h-screen flex flex-col bg-gradient-to-b from-muted/20 to-background">
      <header className="sticky top-0 z-10 border-b px-4 md:px-8 py-3 flex flex-wrap items-center gap-4 justify-between bg-card/90 backdrop-blur supports-[backdrop-filter]:bg-card/80">
        <div className="flex items-center gap-4 min-w-0">
          <span className="text-sm font-semibold tabular-nums text-primary">{formatElapsed(elapsedRef.current)}</span>
          <span className="text-sm font-medium truncate">{question ? sectionTitle(question.section) : "…"}</span>
        </div>
        <div className="flex items-center gap-3 flex-1 max-w-md min-w-[200px]">
          <Progress
            value={
              displayProgress.estimated_total
                ? Math.min(100, (displayProgress.current / displayProgress.estimated_total) * 100)
                : 0
            }
            className="h-2 flex-1"
          />
          <span className="text-xs text-muted-foreground whitespace-nowrap tabular-nums">
            Question {displayProgress.current} of ~{displayProgress.estimated_total || "?"}
          </span>
        </div>
      </header>

      <main className="flex-1 flex items-stretch justify-center p-4 md:p-8">
        <div className="w-full max-w-3xl">
          {initializing || betweenQuestions || !question ? (
            <div className="space-y-4">
              <Skeleton className="h-8 w-3/4" />
              <Skeleton className="h-24 w-full" />
              <Skeleton className="h-10 w-full" />
            </div>
          ) : (
            <Card className="border-0 shadow-lg">
              <CardContent className="pt-8 space-y-8">
                {question.passage_text && (
                  <div className="rounded-lg bg-muted/50 p-4 text-sm leading-relaxed whitespace-pre-wrap">
                    {question.passage_text}
                  </div>
                )}
                <p className="text-lg font-medium leading-snug">{question.stem}</p>

                {(question.type === "mcq" || question.type === "definition_match") && question.options && (
                  <RadioGroup value={singleAnswer} onValueChange={setSingleAnswer} className="space-y-3">
                    {question.options.map((o) => (
                      <label
                        key={o.label}
                        className={cn(
                          "flex cursor-pointer items-center gap-3 rounded-lg border p-4 transition-colors",
                          singleAnswer === o.label && "border-primary bg-primary/5",
                        )}
                      >
                        <RadioGroupItem value={o.label} id={`opt-${o.label}`} />
                        <span className="text-sm leading-snug">{o.text}</span>
                      </label>
                    ))}
                  </RadioGroup>
                )}

                {question.type === "mcq_multi" && question.options && (
                  <div className="space-y-3">
                    {question.options.map((o) => (
                      <label
                        key={o.label}
                        className="flex cursor-pointer items-center gap-3 rounded-lg border p-4"
                      >
                        <Checkbox
                          checked={multiAnswer.includes(o.label)}
                          onCheckedChange={() => toggleMulti(o.label)}
                        />
                        <span className="text-sm">{o.text}</span>
                      </label>
                    ))}
                  </div>
                )}

                {question.type === "gap_fill" && (
                  <Input
                    value={singleAnswer}
                    onChange={(e) => setSingleAnswer(e.target.value)}
                    placeholder="Your answer"
                    className="text-base"
                  />
                )}

                {question.type === "tfng" && (
                  <RadioGroup value={singleAnswer} onValueChange={setSingleAnswer} className="space-y-3">
                    {(question.options?.length
                      ? question.options
                      : [
                          { label: "T", text: "True" },
                          { label: "F", text: "False" },
                          { label: "NG", text: "Not Given" },
                        ]
                    ).map((o) => (
                      <label
                        key={o.label}
                        className={cn(
                          "flex cursor-pointer items-center gap-3 rounded-lg border p-4",
                          singleAnswer === o.label && "border-primary bg-primary/5",
                        )}
                      >
                        <RadioGroupItem value={o.label} id={`tfng-${o.label}`} />
                        <span className="text-sm">{o.text}</span>
                      </label>
                    ))}
                  </RadioGroup>
                )}

                {question.type === "audio_recording" && (
                  <PlacementSpeakingRecorder
                    sessionId={sessionId}
                    promptId={question.id}
                    onUploaded={() => setSingleAnswer("audio_submitted")}
                  />
                )}

                <div className="flex justify-end pt-4">
                  <Button
                    size="lg"
                    className="min-w-[160px]"
                    disabled={answerMut.isPending || betweenQuestions}
                    onClick={() => void submit()}
                  >
                    {answerMut.isPending || betweenQuestions ? (
                      <>
                        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                        Saving
                      </>
                    ) : approxFinal ? (
                      "Finish Test"
                    ) : (
                      "Submit answer"
                    )}
                  </Button>
                </div>
              </CardContent>
            </Card>
          )}
        </div>
      </main>
    </div>
  );
}

function PlacementSpeakingRecorder({ sessionId, promptId, onUploaded }: {
  sessionId: string; promptId: number; onUploaded: () => void;
}) {
  const [recording, setRecording] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [audioUrl, setAudioUrl] = useState<string | null>(null);
  const [elapsed, setElapsed] = useState(0);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);
  const timerRef = useRef<number>(0);

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mr = new MediaRecorder(stream, { mimeType: "audio/webm" });
      chunksRef.current = [];
      mr.ondataavailable = (e) => { if (e.data.size > 0) chunksRef.current.push(e.data); };
      mr.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: "audio/webm" });
        setAudioUrl(URL.createObjectURL(blob));
        stream.getTracks().forEach((t) => t.stop());
        uploadAudio(blob);
      };
      mediaRecorderRef.current = mr;
      mr.start();
      setRecording(true);
      setElapsed(0);
      timerRef.current = window.setInterval(() => setElapsed((t) => t + 1), 1000);
    } catch {
      // microphone permission denied
    }
  };

  const stopRecording = () => {
    mediaRecorderRef.current?.stop();
    setRecording(false);
    window.clearInterval(timerRef.current);
  };

  const uploadAudio = async (blob: Blob) => {
    setUploading(true);
    try {
      const file = new File([blob], "speaking.webm", { type: "audio/webm" });
      await placementService.uploadSpeaking(sessionId, promptId, file);
      onUploaded();
    } catch {
      // upload error handled silently
    } finally {
      setUploading(false);
    }
  };

  const mm = Math.floor(elapsed / 60);
  const ss = elapsed % 60;

  return (
    <div className="flex flex-col items-center gap-4 py-8 rounded-xl border border-dashed bg-muted/30">
      {!recording && !audioUrl && (
        <>
          <Mic className="h-12 w-12 text-muted-foreground" />
          <p className="text-sm text-muted-foreground text-center max-w-sm">
            Click the button below to start recording your speaking response.
          </p>
          <Button type="button" variant="secondary" size="lg" onClick={startRecording} className="gap-2">
            <Mic className="h-5 w-5" /> Start Recording
          </Button>
        </>
      )}
      {recording && (
        <div className="flex flex-col items-center gap-3">
          <div className="flex items-center gap-3">
            <div className="h-3 w-3 rounded-full bg-red-500 animate-pulse" />
            <span className="font-mono text-lg tabular-nums">{String(mm).padStart(2, "0")}:{String(ss).padStart(2, "0")}</span>
          </div>
          <Button type="button" variant="destructive" size="lg" onClick={stopRecording} className="gap-2">
            <Square className="h-4 w-4" /> Stop Recording
          </Button>
        </div>
      )}
      {audioUrl && (
        <div className="space-y-3 w-full max-w-md">
          <audio controls src={audioUrl} className="w-full" />
          {uploading && <p className="text-sm text-center text-muted-foreground flex items-center justify-center gap-2"><Loader2 className="h-4 w-4 animate-spin" /> Uploading...</p>}
          {!uploading && <p className="text-sm text-center text-green-600">Recording uploaded successfully</p>}
        </div>
      )}
    </div>
  );
}
