import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { Play } from 'lucide-react'
import { cn } from '@/lib/utils'
import { useTestStore } from '@/store/test-store'
import { useRequireAuth } from '@/hooks/use-require-auth'
import { TestSessionHeader } from './TestSessionHeader'
import { TestSessionSidebar } from './TestSessionSidebar'
import { TestSessionFooter } from './TestSessionFooter'
import type { Question } from '@/types'

const ANSWER_LABELS = ['A', 'B', 'C', 'D']
const LETTER_PLACEHOLDER_RE =
  /^(Statement|Response|Choice)\s+[A-D]$/i

interface QuestionGroup {
  groupId: number
  questions: Question[]
  passageText?: string
  audioUrl?: string
  imageUrl?: string
}

function groupByGroupId(questions: Question[]): QuestionGroup[] {
  const groups: QuestionGroup[] = []
  for (const q of questions) {
    const last = groups[groups.length - 1]
    if (last && last.groupId === q.groupId) {
      last.questions.push(q)
    } else {
      groups.push({
        groupId: q.groupId,
        questions: [q],
        passageText: q.passageText,
        audioUrl: q.audioUrl,
        imageUrl: q.imageUrl,
      })
    }
  }
  return groups
}

function PassageBlock({ group }: { group: QuestionGroup }) {
  const { audioUrl, imageUrl, passageText } = group

  if (!audioUrl && !imageUrl && !passageText) return null

  return (
    <div
      style={{
        background: 'var(--at-paper-2)',
        borderRadius: 10,
        padding: '18px 20px',
        fontFamily: 'var(--at-mono)',
        fontSize: 12.5,
        lineHeight: 1.7,
        color: 'var(--at-ink-2)',
        marginBottom: 24,
        whiteSpace: 'pre-wrap',
      }}
    >
      {audioUrl && (
        <div className="flex items-center gap-3" style={{ marginBottom: passageText || imageUrl ? 12 : 0 }}>
          <audio
            controls
            src={audioUrl}
            className="w-full"
            style={{ height: 32 }}
          />
        </div>
      )}

      {imageUrl && (
        <div
          style={{
            marginTop: audioUrl ? 12 : 0,
            borderRadius: 8,
            overflow: 'hidden',
            border: '1px solid var(--at-line)',
            aspectRatio: '16 / 9',
            background: '#d8d4c9',
          }}
        >
          <img src={imageUrl} alt="" className="w-full h-full object-contain" />
        </div>
      )}

      {!audioUrl && !imageUrl && (
        // No audio/image → text-only passage (Part 6/7)
        <div>{passageText}</div>
      )}

      {(audioUrl || imageUrl) && passageText && (
        <div style={{ marginTop: 10, fontSize: 12, color: 'var(--at-mute)' }}>{passageText}</div>
      )}
    </div>
  )
}

function AudioPlaceholder({ label }: { label: string }) {
  return (
    <div
      className="flex items-center gap-3"
      style={{
        background: 'var(--at-surface)',
        border: '1px solid var(--at-line)',
        borderRadius: 10,
        padding: '14px 16px',
        marginBottom: 24,
      }}
    >
      <button
        className="grid place-items-center"
        style={{
          width: 34,
          height: 34,
          borderRadius: 999,
          background: 'var(--at-brand)',
          color: 'white',
        }}
      >
        <Play size={14} fill="white" />
      </button>
      <div className="flex-1">
        <div
          style={{
            fontFamily: 'var(--at-serif)',
            fontStyle: 'italic',
            fontSize: 12,
            letterSpacing: '0.08em',
            textTransform: 'uppercase',
            color: 'var(--at-mute)',
            marginBottom: 2,
          }}
        >
          {label}
        </div>
        <div
          style={{
            height: 4,
            background: 'var(--at-line)',
            borderRadius: 2,
            overflow: 'hidden',
          }}
        >
          <span style={{ display: 'block', width: 0, height: '100%' }} />
        </div>
      </div>
    </div>
  )
}

function QuestionBlock({
  question, globalNum, answer, onSelect, isFirst, registerRef,
}: {
  question: Question
  globalNum: number
  answer: number | null
  onSelect: (idx: number) => void
  isFirst: boolean
  registerRef: (el: HTMLDivElement | null) => void
}) {
  return (
    <div
      ref={registerRef}
      data-qid={question.id}
      style={{
        padding: '16px 0',
        borderTop: isFirst ? 'none' : '1px solid var(--at-line)',
        paddingTop: isFirst ? 4 : 16,
        scrollMarginTop: 24,
      }}
    >
      <div style={{ marginBottom: 10 }}>
        <span
          className="inline-block"
          style={{
            background: 'var(--at-brand-soft)',
            color: 'var(--at-brand)',
            padding: '4px 10px',
            borderRadius: 6,
            fontSize: 12,
            fontWeight: 600,
          }}
        >
          Câu {globalNum}
        </span>
      </div>

      {question.text && (
        <p
          style={{
            fontSize: 15,
            lineHeight: 1.5,
            color: 'var(--at-ink)',
            marginBottom: 14,
            fontWeight: 500,
          }}
        >
          {question.text}
        </p>
      )}

      <div className="grid gap-2">
        {question.options.map((opt, i) => {
          const letter = ANSWER_LABELS[i]
          const isSelected = answer === i
          const hideText = !question.text && LETTER_PLACEHOLDER_RE.test(opt)

          return (
            <button
              key={i}
              onClick={() => onSelect(i)}
              className={cn('flex items-center gap-3 text-left transition-all')}
              style={{
                padding: hideText ? '14px 18px' : '12px 16px',
                minHeight: hideText ? 44 : undefined,
                background: isSelected ? 'var(--at-brand-soft)' : 'var(--at-surface)',
                border: `1px solid ${isSelected ? 'var(--at-brand)' : 'var(--at-line)'}`,
                borderRadius: 10,
                fontSize: 14,
                color: 'var(--at-ink)',
              }}
            >
              <span
                className="grid place-items-center flex-shrink-0"
                style={{
                  width: 28,
                  height: 28,
                  borderRadius: 999,
                  background: isSelected ? 'var(--at-brand)' : 'var(--at-surface)',
                  border: `1px solid ${isSelected ? 'var(--at-brand)' : 'var(--at-line)'}`,
                  color: isSelected ? '#fff' : 'var(--at-ink-2)',
                  fontWeight: 600,
                  fontSize: 12,
                }}
              >
                {letter}
              </span>
              {!hideText && <span>{opt}</span>}
            </button>
          )
        })}
      </div>
    </div>
  )
}

function GroupCard({
  group, globalOffset, startIndex, answers, onSelect, registerQuestionRef,
}: {
  group: QuestionGroup
  globalOffset: number
  startIndex: number
  answers: Record<number, number | null>
  onSelect: (qid: number, idx: number) => void
  registerQuestionRef: (qid: number, el: HTMLDivElement | null) => void
}) {
  const hasAudio = !!group.audioUrl

  return (
    <div
      style={{
        background: 'var(--at-surface)',
        border: '1px solid var(--at-line)',
        borderRadius: 12,
        padding: '24px 28px',
        marginBottom: 20,
      }}
    >
      {hasAudio && !group.imageUrl && !group.passageText && (
        <AudioPlaceholder label={`Audio · Câu ${globalOffset + startIndex + 1}`} />
      )}
      <PassageBlock group={group} />

      {group.questions.map((q, i) => (
        <QuestionBlock
          key={q.id}
          question={q}
          globalNum={globalOffset + startIndex + i + 1}
          answer={answers[q.id] ?? null}
          onSelect={(idx) => onSelect(q.id, idx)}
          isFirst={i === 0 && !hasAudio && !group.imageUrl && !group.passageText}
          registerRef={(el) => registerQuestionRef(q.id, el)}
        />
      ))}
    </div>
  )
}

export function TestSession() {
  const navigate = useNavigate()
  const {
    testName, parts, currentPartIndex, answers, totalSeconds,
    setAnswer, setCurrentPart, submitExam,
  } = useTestStore()
  const { isAuthenticated, isLoading } = useRequireAuth()
  const [timeLeft, setTimeLeft] = useState(() => (totalSeconds > 0 ? totalSeconds : -1))
  const [timeUsed, setTimeUsed] = useState(0)

  // Map of questionId → DOM node, so sidebar clicks can scroll to a specific question.
  const questionRefs = useRef<Map<number, HTMLDivElement>>(new Map())
  // When jumping to a question in another part, we switch part first, then scroll
  // after the new part renders. `pendingScrollQid` holds the target until mount.
  const [pendingScrollQid, setPendingScrollQid] = useState<number | null>(null)

  const registerQuestionRef = useCallback((qid: number, el: HTMLDivElement | null) => {
    if (el) questionRefs.current.set(qid, el)
    else questionRefs.current.delete(qid)
  }, [])

  function scrollToQuestion(qid: number) {
    const el = questionRefs.current.get(qid)
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
  }

  function jumpToQuestion(qid: number) {
    // Find part that owns this question.
    const targetPartIndex = parts.findIndex(p => p.questions.some(q => q.id === qid))
    if (targetPartIndex === -1) return
    if (targetPartIndex !== currentPartIndex) {
      setCurrentPart(targetPartIndex)
      setPendingScrollQid(qid)
    } else {
      scrollToQuestion(qid)
    }
  }

  // After a part change, if we have a pending scroll target, run it.
  useEffect(() => {
    if (pendingScrollQid === null) return
    // Wait one frame so refs are registered for the newly mounted part.
    const raf = requestAnimationFrame(() => {
      scrollToQuestion(pendingScrollQid)
      setPendingScrollQid(null)
    })
    return () => cancelAnimationFrame(raf)
  }, [currentPartIndex, pendingScrollQid])

  const totalQuestions = useMemo(
    () => parts.reduce((sum, p) => sum + p.questions.length, 0),
    [parts],
  )
  const answeredCount = useMemo(
    () => Object.values(answers).filter((v) => v !== null && v !== undefined).length,
    [answers],
  )

  const [showSubmitConfirm, setShowSubmitConfirm] = useState(false)

  const handleSubmit = useCallback(() => {
    submitExam(totalSeconds > 0 ? totalSeconds - timeLeft : timeUsed)
    navigate({ to: '/toeic/result' })
  }, [submitExam, navigate, totalSeconds, timeLeft, timeUsed])

  // Manual click → confirm if any unanswered; auto (timer expire) skips confirm.
  const requestSubmit = useCallback(() => {
    if (totalQuestions > 0 && answeredCount < totalQuestions) {
      setShowSubmitConfirm(true)
    } else {
      handleSubmit()
    }
  }, [totalQuestions, answeredCount, handleSubmit])

  useEffect(() => {
    if (parts.length === 0) return
    const id = setInterval(() => {
      if (timeLeft > 0) {
        setTimeLeft((t) => {
          if (t <= 1) {
            clearInterval(id)
            handleSubmit()
            return 0
          }
          return t - 1
        })
      } else {
        setTimeUsed((t) => t + 1)
      }
    }, 1000)
    return () => clearInterval(id)
  }, [parts.length, timeLeft, handleSubmit])

  useEffect(() => {
    if (isLoading) return
    if (!isAuthenticated || parts.length === 0) navigate({ to: '/toeic' })
  }, [isLoading, isAuthenticated, parts.length, navigate])

  if (parts.length === 0) return null

  const currentPart = parts[currentPartIndex]

  let globalOffset = 0
  for (let i = 0; i < currentPartIndex; i++) globalOffset += parts[i].questions.length

  const groups = groupByGroupId(currentPart.questions)

  return (
    <div
      className="flex flex-col"
      style={{
        height: 'calc(100vh - var(--app-header-height, 0px))',
        background: 'var(--at-paper-2)',
      }}
    >
      <TestSessionHeader
        testName={testName}
        timeLeft={timeLeft}
        timeUsed={timeUsed}
        totalQuestions={totalQuestions}
        answeredCount={answeredCount}
        onSubmit={requestSubmit}
      />

      <div className="flex flex-1 overflow-hidden">
        <TestSessionSidebar
          parts={parts}
          currentPartIndex={currentPartIndex}
          answers={answers}
          onSelectPart={setCurrentPart}
          onSelectQuestion={jumpToQuestion}
        />

        <main
          className="flex-1 overflow-y-auto"
          style={{ padding: '24px 32px 80px' }}
        >
          <div className="mx-auto w-full" style={{ maxWidth: 880 }}>
            <div style={{ marginBottom: 18 }}>
              <div
                style={{
                  fontFamily: 'var(--at-serif)',
                  fontStyle: 'italic',
                  fontSize: 12,
                  letterSpacing: '0.08em',
                  textTransform: 'uppercase',
                  color: 'var(--at-mute)',
                  marginBottom: 8,
                }}
              >
                Đang làm
              </div>
              <div
                style={{
                  fontFamily: 'var(--at-serif)',
                  fontSize: 22,
                  fontWeight: 400,
                  letterSpacing: '-0.015em',
                  color: 'var(--at-ink)',
                }}
              >
                Part {currentPart.partNumber}:{' '}
                <i style={{ fontStyle: 'italic', color: 'var(--at-ink-2)' }}>
                  {currentPart.partName}
                </i>
              </div>
            </div>

            {groups.length === 0 && (
              <div
                style={{
                  background: 'var(--at-surface)',
                  border: '1px dashed var(--at-line)',
                  borderRadius: 12,
                  padding: 40,
                  textAlign: 'center',
                }}
              >
                <div
                  style={{
                    fontFamily: 'var(--at-serif)',
                    fontSize: 18,
                    fontStyle: 'italic',
                    color: 'var(--at-mute)',
                  }}
                >
                  Part này chưa có dữ liệu.
                </div>
              </div>
            )}

            {groups.map((group) => {
              let startIndex = 0
              for (const g of groups) {
                if (g === group) break
                startIndex += g.questions.length
              }
              return (
                <GroupCard
                  key={group.groupId}
                  group={group}
                  globalOffset={globalOffset}
                  startIndex={startIndex}
                  answers={answers}
                  onSelect={setAnswer}
                  registerQuestionRef={registerQuestionRef}
                />
              )
            })}
          </div>
        </main>
      </div>

      <TestSessionFooter
        currentPartIndex={currentPartIndex}
        totalParts={parts.length}
        currentPartName={currentPart.partName}
        onPrev={() => setCurrentPart(currentPartIndex - 1)}
        onNext={() => setCurrentPart(currentPartIndex + 1)}
      />

      {showSubmitConfirm && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center px-4"
          style={{ background: 'rgba(15, 17, 20, 0.5)' }}
          onClick={() => setShowSubmitConfirm(false)}
        >
          <div
            className="w-full max-w-md rounded-2xl p-6 shadow-2xl"
            style={{ background: 'var(--at-surface)', border: '1px solid var(--at-line)' }}
            onClick={(e) => e.stopPropagation()}
          >
            <div
              className="at-serif"
              style={{ fontSize: 22, fontWeight: 500, letterSpacing: '-0.02em', color: 'var(--at-ink)', marginBottom: 8 }}
            >
              Nộp bài <i style={{ fontStyle: 'italic', color: 'var(--at-brand)' }}>ngay?</i>
            </div>
            <p style={{ fontSize: 14, color: 'var(--at-mute)', lineHeight: 1.55, marginBottom: 20 }}>
              Bạn còn{' '}
              <b style={{ color: 'var(--at-bad)' }}>{totalQuestions - answeredCount}</b>/{totalQuestions} câu
              chưa trả lời. Các câu chưa trả lời sẽ tính là{' '}
              <b>bỏ qua</b> và không có điểm.
            </p>
            <div className="flex gap-2 justify-end">
              <button
                onClick={() => setShowSubmitConfirm(false)}
                className="px-4 py-2 rounded-lg text-sm font-semibold transition-colors hover:bg-[var(--at-line-2)]"
                style={{ background: 'var(--at-surface)', border: '1px solid var(--at-line)', color: 'var(--at-ink-2)' }}
              >
                Tiếp tục làm
              </button>
              <button
                onClick={() => { setShowSubmitConfirm(false); handleSubmit() }}
                className="px-4 py-2 rounded-lg text-sm font-semibold text-white transition-[filter] hover:brightness-110"
                style={{ background: '#e53935' }}
              >
                Nộp bài
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}
