import { useState, useEffect, useRef, useCallback } from 'react';
import {
  Loader, AlertCircle, Trophy, ArrowRight, ArrowLeft,
  Clock, CheckCircle, XCircle, BookOpen, Layers,
} from 'lucide-react';

// Pure helper: bucket the eligible topics by their `theme` field. Topics with
// no theme land in a single "No theme" group, rendered last. Each bucket is
// alphabetised by topic label for stable display.
function groupEligibleByTheme(topics) {
  const buckets = new Map();
  for (const t of topics) {
    const key = t.theme || '__no_theme__';
    if (!buckets.has(key)) buckets.set(key, { theme: t.theme || 'No theme', topics: [] });
    buckets.get(key).topics.push(t);
  }
  const out = [];
  let noTheme = null;
  for (const [key, val] of buckets.entries()) {
    val.topics.sort((a, b) => (a.label || '').localeCompare(b.label || ''));
    if (key === '__no_theme__') noTheme = val;
    else out.push(val);
  }
  out.sort((a, b) => a.theme.localeCompare(b.theme));
  return noTheme ? [...out, noTheme] : out;
}
import { motion, AnimatePresence } from 'framer-motion';
import { Link } from 'react-router-dom';
import Card from '../components/ui/Card';
import Button from '../components/ui/Button';
import Tag from '../components/ui/Tag';
import { useApp } from '../store/AppContext';
import {
  getEligibleTopicsForOnDemand,
  startOnDemandTest,
  finishOnDemandTest,
  ON_DEMAND_TEST_SIZE,
  WEEKLY_POINT_CAP_PER_TOPIC,
} from '../lib/testService';

const TIMER_SECONDS = 300;

function formatTime(sec) {
  const m = Math.floor(sec / 60);
  const s = sec % 60;
  return `${m}:${s.toString().padStart(2, '0')}`;
}

const TopicTest = () => {
  const { state } = useApp();
  const { currentUser } = state;

  const [phase, setPhase] = useState('picker'); // picker | loading | quiz | results
  const [topics, setTopics] = useState([]);
  const [topicsLoading, setTopicsLoading] = useState(true);
  const [pickedTopic, setPickedTopic] = useState(null);
  const [quiz, setQuiz] = useState(null);
  const [answers, setAnswers] = useState({});
  const [currentQ, setCurrentQ] = useState(0);
  const [showFeedback, setShowFeedback] = useState(false);
  const [timeLeft, setTimeLeft] = useState(TIMER_SECONDS);
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);
  const timerRef = useRef(null);

  // ── Load eligible topics for the picker ──
  useEffect(() => {
    if (phase !== 'picker' || !currentUser) return;
    let cancelled = false;
    (async () => {
      setTopicsLoading(true);
      try {
        const eligible = await getEligibleTopicsForOnDemand();
        if (!cancelled) setTopics(eligible);
      } catch (e) {
        if (!cancelled) setError(e.message);
      } finally {
        if (!cancelled) setTopicsLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [phase, currentUser]);

  // ── Timer ──
  const finishRef = useRef(null);
  useEffect(() => {
    if (phase === 'quiz') {
      timerRef.current = setInterval(() => {
        setTimeLeft(prev => {
          if (prev <= 1) {
            clearInterval(timerRef.current);
            finishRef.current?.();
            return 0;
          }
          return prev - 1;
        });
      }, 1000);
    }
    return () => clearInterval(timerRef.current);
  }, [phase]);

  // ── Start a test on the picked topic ──
  const startTest = async (topic) => {
    setPickedTopic(topic);
    setPhase('loading');
    setError(null);
    try {
      const q = await startOnDemandTest(currentUser.id, topic.id);
      if (!q?.questions?.length) throw new Error('Could not pull questions from the bank for this topic.');
      setQuiz(q);
      setAnswers({});
      setCurrentQ(0);
      setShowFeedback(false);
      setTimeLeft(TIMER_SECONDS);
      setPhase('quiz');
    } catch (e) {
      setError(e.message);
      setPhase('picker');
    }
  };

  // ── Pick an answer ──
  const selectAnswer = (questionId, optionIndex) => {
    if (showFeedback) return;
    setAnswers(prev => ({ ...prev, [questionId]: optionIndex }));
    setShowFeedback(true);
  };

  const nextQuestion = () => {
    setShowFeedback(false);
    if (currentQ < quiz.questions.length - 1) {
      setCurrentQ(p => p + 1);
    } else {
      finishTest();
    }
  };

  const finishTest = useCallback(async () => {
    clearInterval(timerRef.current);
    if (!quiz || !pickedTopic) return;
    try {
      const r = await finishOnDemandTest(
        currentUser.id,
        pickedTopic.id,
        pickedTopic.label,
        quiz,
        answers,
        TIMER_SECONDS - timeLeft,
      );
      setResult(r);
      setPhase('results');
    } catch (e) {
      setError(e.message);
      setPhase('picker');
    }
  }, [quiz, pickedTopic, answers, timeLeft, currentUser]);

  useEffect(() => { finishRef.current = finishTest; }, [finishTest]);

  const resetToPicker = () => {
    setQuiz(null);
    setResult(null);
    setPickedTopic(null);
    setAnswers({});
    setCurrentQ(0);
    setShowFeedback(false);
    setError(null);
    setPhase('picker');
  };

  // ─── Picker ────────────────────────────────────────────────
  if (phase === 'picker') {
    return (
      <div className="p-4 md:p-8 max-w-3xl mx-auto pb-24 md:pb-8">
        <div className="mb-8">
          <h1 className="text-3xl md:text-4xl font-bold text-teal mb-2">Topic Test</h1>
          <p className="text-fg-muted">
            Pick any topic and take a {ON_DEMAND_TEST_SIZE}-question test on demand.
            You can earn up to {WEEKLY_POINT_CAP_PER_TOPIC} points per topic per week.
          </p>
        </div>

        {error && (
          <Card className="border border-red-200 bg-red-50 text-red-900 p-4 mb-6 text-sm">
            <div className="flex items-start gap-2">
              <AlertCircle size={16} className="flex-shrink-0 mt-0.5" />
              <p>{error}</p>
            </div>
          </Card>
        )}

        {topicsLoading ? (
          <div className="text-center py-20">
            <Loader size={36} className="mx-auto text-teal animate-spin mb-3" />
            <p className="text-fg-muted text-sm">Loading available topics…</p>
          </div>
        ) : topics.length === 0 ? (
          <Card className="border border-dashed border-bg-warm text-center py-16 text-fg-muted">
            <BookOpen size={48} className="mx-auto mb-4 text-teal/30" />
            <p className="font-medium text-fg mb-1">No topics available yet.</p>
            <p className="text-sm">An admin needs to add at least {ON_DEMAND_TEST_SIZE} questions to a topic's bank before you can test on it.</p>
          </Card>
        ) : (
          <div className="space-y-8">
            {groupEligibleByTheme(topics).map(group => (
              <section key={group.theme}>
                <div className="flex items-center gap-2 mb-3">
                  <Layers size={16} className="text-teal/70" />
                  <h3 className="text-lg font-bold text-fg">{group.theme}</h3>
                  <span className="font-mono text-[11px] text-fg-muted ml-1">
                    {group.topics.length} {group.topics.length === 1 ? 'topic' : 'topics'}
                  </span>
                </div>
                <div className="space-y-3">
                  {group.topics.map(topic => (
                    <Card key={topic.id} className="border border-bg-warm flex items-center justify-between gap-4">
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-2 mb-1 flex-wrap">
                          <h4 className="font-semibold truncate">{topic.label}</h4>
                          <Tag variant="success" className="text-xs">{topic.bankSize} questions</Tag>
                        </div>
                        {topic.description && (
                          <p className="text-sm text-fg-muted truncate">{topic.description}</p>
                        )}
                      </div>
                      <Button onClick={() => startTest(topic)} className="flex-shrink-0">
                        Start <ArrowRight size={16} className="ml-1.5" />
                      </Button>
                    </Card>
                  ))}
                </div>
              </section>
            ))}
          </div>
        )}
      </div>
    );
  }

  // ─── Loading ───────────────────────────────────────────────
  if (phase === 'loading') {
    return (
      <div className="p-4 md:p-8 max-w-2xl mx-auto text-center py-20">
        <Loader size={48} className="mx-auto text-teal animate-spin mb-4" />
        <p className="font-medium text-lg">Drawing questions from the bank…</p>
        <p className="text-sm text-fg-muted mt-2">No AI call — these are shared, admin-curated questions.</p>
      </div>
    );
  }

  // ─── Results ───────────────────────────────────────────────
  if (phase === 'results' && result) {
    const isPerfect = result.percentage === 100;
    const isGood = result.percentage >= 70;
    const hasRepeats = result.breakdown.some(b => !b.isUnseen);

    return (
      <div className="p-4 md:p-8 max-w-3xl mx-auto pb-24 md:pb-8">
        <motion.div
          initial={{ scale: 0.8, opacity: 0 }}
          animate={{ scale: 1, opacity: 1 }}
          className="text-center mb-10"
        >
          <div className={`inline-flex items-center justify-center w-28 h-28 rounded-full mb-6 ${
            isPerfect ? 'bg-teal text-white' : isGood ? 'bg-teal/10 text-teal' : 'bg-orange-100 text-orange-600'
          }`}>
            <span className="text-4xl font-bold">{result.percentage}%</span>
          </div>
          <h1 className="text-3xl font-bold mb-2">
            {isPerfect ? 'Perfect score!' : isGood ? 'Well done!' : 'Keep learning!'}
          </h1>
          <p className="text-fg-muted">
            {pickedTopic?.label} · {result.score}/{result.total} in {formatTime(result.timeUsed)}.
            {result.pointsEarned > 0 && (
              <span className="text-teal font-semibold"> +{result.pointsEarned} pts</span>
            )}
          </p>
        </motion.div>

        {/* Capped / repeats notice */}
        {(result.capped || hasRepeats) && (
          <Card className="border border-orange-200 bg-orange-50 text-orange-900 mb-6 text-sm">
            <div className="flex items-start gap-2">
              <AlertCircle size={16} className="flex-shrink-0 mt-0.5" />
              <div>
                {result.capped && (
                  <p className="font-medium">
                    Weekly cap reached: you've already earned the maximum {WEEKLY_POINT_CAP_PER_TOPIC} pts for this topic this week.
                    {result.rawPoints > result.pointsEarned && ` Practice points earned: ${result.rawPoints - result.pointsEarned} (not counted).`}
                  </p>
                )}
                {hasRepeats && !result.capped && (
                  <p>
                    Some questions were repeats — you've seen them before. Repeats are practice only and don't add to your point total.
                  </p>
                )}
              </div>
            </div>
          </Card>
        )}

        <div className="grid grid-cols-3 gap-4 mb-8">
          <Card className="border border-bg-warm text-center py-4">
            <CheckCircle size={24} className="mx-auto text-teal mb-1" />
            <div className="text-2xl font-bold text-teal">{result.score}</div>
            <div className="text-xs text-fg-muted">Correct</div>
          </Card>
          <Card className="border border-bg-warm text-center py-4">
            <XCircle size={24} className="mx-auto text-red-400 mb-1" />
            <div className="text-2xl font-bold text-red-500">{result.total - result.score}</div>
            <div className="text-xs text-fg-muted">Incorrect</div>
          </Card>
          <Card className="border border-bg-warm text-center py-4">
            <Trophy size={24} className="mx-auto text-fg-muted mb-1" />
            <div className="text-2xl font-bold">{result.pointsEarned}</div>
            <div className="text-xs text-fg-muted">Points</div>
          </Card>
        </div>

        <div className="flex items-center justify-between mb-4 flex-wrap gap-2">
          <h2 className="text-xl font-bold">Question Review</h2>
          <div className="flex gap-2">
            <Button variant="outline" onClick={resetToPicker}>
              <ArrowLeft size={16} className="mr-1.5" /> Another topic
            </Button>
            <Link to="/leaderboard">
              <Button variant="outline"><Trophy size={16} className="mr-2" /> Leaderboard</Button>
            </Link>
          </div>
        </div>

        <div className="space-y-4">
          {result.breakdown.map((item, i) => (
            <Card key={i} className={`border ${item.correct ? 'border-teal/30' : 'border-red-200'}`}>
              <div className="flex items-start gap-3 mb-3">
                <div className={`flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${
                  item.correct ? 'bg-teal/10 text-teal' : 'bg-red-50 text-red-500'
                }`}>
                  {i + 1}
                </div>
                <div className="flex-1">
                  <p className="font-medium">{item.question}</p>
                  <div className="flex items-center gap-2 mt-0.5">
                    <p className="text-xs text-fg-muted">{item.topicLabel}</p>
                    {!item.isUnseen && (
                      <Tag variant="dark" className="text-[10px]">Repeat (no points)</Tag>
                    )}
                  </div>
                </div>
              </div>

              <div className="grid grid-cols-1 sm:grid-cols-2 gap-2 ml-10 mb-3">
                {item.options.map((opt, oi) => {
                  const isCorrect = oi === item.correctIndex;
                  const wasSelected = oi === item.selected;
                  return (
                    <div
                      key={oi}
                      className={`px-3 py-2 rounded-[var(--r-sm)] text-sm border ${
                        isCorrect
                          ? 'border-teal bg-teal/5 text-teal font-medium'
                          : wasSelected
                            ? 'border-red-300 bg-red-50 text-red-700'
                            : 'border-bg-warm text-fg-muted'
                      }`}
                    >
                      {isCorrect && <CheckCircle size={14} className="inline mr-1 -mt-0.5" />}
                      {wasSelected && !isCorrect && <XCircle size={14} className="inline mr-1 -mt-0.5" />}
                      {opt}
                    </div>
                  );
                })}
              </div>
              <p className="text-sm text-fg-muted ml-10 italic">{item.explanation}</p>
            </Card>
          ))}
        </div>
      </div>
    );
  }

  // ─── Active Quiz ───────────────────────────────────────────
  if (phase === 'quiz' && quiz) {
    const q = quiz.questions[currentQ];
    if (!q) {
      return (
        <div className="p-4 md:p-8 max-w-2xl mx-auto text-center py-20">
          <p className="text-red-500 font-medium">Something went wrong loading this question.</p>
          <Button className="mt-4" onClick={resetToPicker}>Back</Button>
        </div>
      );
    }

    const selectedAnswer = answers[q.id];
    const isCorrect = selectedAnswer === q.correctIndex;
    const progress = ((currentQ + (showFeedback ? 1 : 0)) / quiz.questions.length) * 100;
    const timerDanger = timeLeft < 60;

    return (
      <div className="p-4 md:p-8 max-w-2xl mx-auto pb-24 md:pb-8">
        <div className="flex items-center justify-between mb-2">
          <span className="font-mono text-sm text-fg-muted">
            Question {currentQ + 1} of {quiz.questions.length}
          </span>
          <span className={`font-mono text-sm font-medium flex items-center gap-1.5 ${
            timerDanger ? 'text-red-500 animate-pulse' : 'text-fg-muted'
          }`}>
            <Clock size={14} /> {formatTime(timeLeft)}
          </span>
        </div>

        <div className="h-1.5 bg-bg-warm rounded-full mb-8 overflow-hidden">
          <motion.div
            className="h-full bg-teal rounded-full"
            initial={false}
            animate={{ width: `${progress}%` }}
            transition={{ duration: 0.3 }}
          />
        </div>

        <AnimatePresence mode="wait">
          <motion.div
            key={q.id}
            initial={{ opacity: 0, x: 30 }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: -30 }}
            transition={{ duration: 0.25 }}
          >
            <Card className="border border-bg-warm mb-6">
              <div className="flex items-center gap-2 mb-4 flex-wrap">
                <Tag variant="accent" className="text-xs">{pickedTopic?.label}</Tag>
                {!q.isUnseen && <Tag variant="dark" className="text-[10px]">Practice (no points)</Tag>}
              </div>
              <h3 className="text-base font-bold leading-snug">{q.question}</h3>
            </Card>

            <div className="space-y-3">
              {q.options.map((option, oi) => {
                let optionClass = 'border-bg-warm bg-paper hover:border-teal/50 hover:bg-teal/5 cursor-pointer';
                if (showFeedback) {
                  if (oi === q.correctIndex) {
                    optionClass = 'border-teal bg-teal/10 text-teal';
                  } else if (oi === selectedAnswer && !isCorrect) {
                    optionClass = 'border-red-300 bg-red-50 text-red-700';
                  } else {
                    optionClass = 'border-bg-warm text-fg-muted opacity-50';
                  }
                } else if (selectedAnswer === oi) {
                  optionClass = 'border-teal bg-teal/5';
                }
                return (
                  <button
                    key={oi}
                    onClick={() => selectAnswer(q.id, oi)}
                    disabled={showFeedback}
                    className={`w-full text-left p-4 rounded-[var(--r-sm)] border transition-all flex items-center gap-3 ${optionClass}`}
                  >
                    <span className="flex-shrink-0 w-8 h-8 rounded-full border border-current flex items-center justify-center font-mono font-bold text-sm">
                      {String.fromCharCode(65 + oi)}
                    </span>
                    <span className="text-sm font-medium">{option.replace(/^[A-D]\)\s*/, '')}</span>
                    {showFeedback && oi === q.correctIndex && <CheckCircle size={18} className="ml-auto text-teal" />}
                    {showFeedback && oi === selectedAnswer && !isCorrect && oi !== q.correctIndex && <XCircle size={18} className="ml-auto text-red-400" />}
                  </button>
                );
              })}
            </div>

            {showFeedback && (
              <motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} className="mt-6">
                <Card className={`border ${isCorrect ? 'border-teal/30 bg-teal/5' : 'border-red-200 bg-red-50'}`}>
                  <div className="flex items-start gap-3">
                    {isCorrect
                      ? <CheckCircle size={20} className="text-teal flex-shrink-0 mt-0.5" />
                      : <XCircle size={20} className="text-red-500 flex-shrink-0 mt-0.5" />}
                    <div>
                      <p className={`font-bold text-sm ${isCorrect ? 'text-teal' : 'text-red-700'}`}>
                        {isCorrect ? 'Correct!' : 'Incorrect'}
                      </p>
                      <p className="text-sm mt-1">{q.explanation}</p>
                    </div>
                  </div>
                </Card>
                <div className="flex justify-end mt-4">
                  <Button onClick={nextQuestion}>
                    {currentQ < quiz.questions.length - 1
                      ? <>Next Question <ArrowRight size={18} className="ml-2" /></>
                      : <>Finish Test <Trophy size={18} className="ml-2" /></>}
                  </Button>
                </div>
              </motion.div>
            )}
          </motion.div>
        </AnimatePresence>
      </div>
    );
  }

  return null;
};

export default TopicTest;
