import { useEffect, useState } from "react"
import type {
  QuizPerPlayerResult,
  QuizQuestionPayload,
  QuizRevealTruth,
  RoomSnapshot,
} from "@nerdware/shared"
import { Button } from "@workspace/ui/components/button"
import { useRoomStore } from "@/store/room"
import { Countdown } from "@/components/countdown"
import { useI18n, type Dict } from "@/i18n/context"

const inputClass =
  "border-input bg-background h-10 w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50"

const SERVER_URL = import.meta.env.VITE_SERVER_URL ?? "http://localhost:3001"
const MAX_BLUR = 22

export function QuizView({ snapshot }: { snapshot: RoomSnapshot }) {
  const round = useRoomStore((s) => s.round)
  const reveal = useRoomStore((s) => s.reveal)
  const voteProgress = useRoomStore((s) => s.voteProgress)
  const myChoiceIndex = useRoomStore((s) => s.myChoiceIndex)
  const hasVoted = useRoomStore((s) => s.hasVoted)
  const playerId = useRoomStore((s) => s.playerId)
  const vote = useRoomStore((s) => s.vote)
  const voteText = useRoomStore((s) => s.voteText)
  const { t } = useI18n()

  if (!round) {
    return <p className="text-muted-foreground text-sm">{t.common.loading}</p>
  }

  const question = round.payload as QuizQuestionPayload
  const truth = reveal ? (reveal.truth as QuizRevealTruth) : null
  const showReveal = truth !== null
  const isImage = question.format === "image_reveal"
  const isRebus = question.format === "rebus"
  const isText = question.format === "free" || isImage || isRebus
  const myResult = reveal
    ? (reveal.perPlayerResult as QuizPerPlayerResult)[playerId ?? ""]
    : undefined

  function choiceClass(index: number): string {
    const base =
      "w-full rounded-lg border px-4 py-3 text-left text-sm transition-colors"
    if (showReveal) {
      if (index === truth?.correctIndex) {
        return `${base} border-green-500 bg-green-500/15 font-medium`
      }
      if (index === myChoiceIndex) {
        return `${base} border-red-500 bg-red-500/10`
      }
      return `${base} border-input opacity-60`
    }
    if (index === myChoiceIndex) {
      return `${base} border-primary bg-primary/10 font-medium`
    }
    return `${base} border-input hover:bg-muted/60`
  }

  return (
    <div className="flex w-full max-w-lg flex-col gap-5">
      <header className="flex items-center justify-between">
        <span className="text-muted-foreground text-xs uppercase">
          {t.game.question(snapshot.currentRound + 1, snapshot.totalRounds)}
          {question.category ? ` · ${question.category}` : ""}
        </span>
        {!showReveal && (
          <Countdown
            key={round.endsAt}
            startsAt={round.startsAt}
            endsAt={round.endsAt}
          />
        )}
      </header>

      {isRebus ? (
        <div className="bg-card flex min-h-32 items-center justify-center rounded-2xl p-6 text-center text-4xl leading-relaxed text-balance sm:text-5xl">
          {question.prompt}
        </div>
      ) : (
        <h2 className="font-heading text-xl font-semibold text-balance">
          {question.prompt}
        </h2>
      )}

      {isImage && question.imageUrl && (
        <ImageReveal
          src={
            question.imageUrl.startsWith("http")
              ? question.imageUrl
              : `${SERVER_URL}${question.imageUrl}`
          }
          startsAt={round.startsAt}
          endsAt={round.endsAt}
          revealed={showReveal}
        />
      )}

      {isText ? (
        <FreeAnswer
          key={round.endsAt}
          disabled={showReveal || hasVoted}
          onSubmit={voteText}
          t={t}
        />
      ) : (
        <div className="flex flex-col gap-2">
          {(question.choices ?? []).map((choice, index) => (
            <button
              key={index}
              className={choiceClass(index)}
              disabled={showReveal || hasVoted}
              onClick={() => vote(index)}
            >
              {choice}
            </button>
          ))}
        </div>
      )}

      {!showReveal &&
        (hasVoted ? (
          <p className="text-muted-foreground text-center text-xs">
            {t.game.answerSent}
            {voteProgress ? ` (${voteProgress.count}/${voteProgress.total})` : ""}
          </p>
        ) : (
          voteProgress && (
            <p className="text-muted-foreground text-center text-xs">
              {t.game.answeredCount(voteProgress.count, voteProgress.total)}
            </p>
          )
        ))}

      {showReveal && (
        <div className="flex flex-col items-center gap-1">
          {isText && (
            <p className="text-sm">
              <span className="text-muted-foreground">{t.game.answer} </span>
              <span className="font-medium">{truth?.answer}</span>
            </p>
          )}
          <p
            className={`text-center text-sm font-medium ${myResult?.correct ? "text-green-500" : "text-red-500"}`}
          >
            {myResult?.correct
              ? t.game.correct
              : !hasVoted
                ? t.game.noAnswer
                : t.game.wrong}
          </p>
        </div>
      )}
    </div>
  )
}

function ImageReveal({
  src,
  startsAt,
  endsAt,
  revealed,
}: {
  src: string
  startsAt: number
  endsAt: number
  revealed: boolean
}) {
  // Le flou décroît avec le temps (cadencé par les timestamps serveur) : tous
  // les clients voient le même niveau de flou au même instant.
  const [blur, setBlur] = useState(MAX_BLUR)

  useEffect(() => {
    if (revealed) {
      return
    }
    const id = setInterval(() => {
      const now = Date.now()
      const p =
        now < startsAt ? 0 : Math.min(1, (now - startsAt) / (endsAt - startsAt))
      setBlur(MAX_BLUR * (1 - p))
    }, 200)
    return () => clearInterval(id)
  }, [revealed, startsAt, endsAt])

  const displayBlur = revealed ? 0 : blur

  return (
    <div className="bg-card relative flex w-full justify-center overflow-hidden rounded-2xl p-2">
      <img
        src={src}
        alt=""
        className="max-h-[58vh] w-auto max-w-full rounded-lg object-contain transition-[filter] duration-300"
        style={{ filter: `blur(${displayBlur}px)` }}
      />
    </div>
  )
}

function FreeAnswer({
  disabled,
  onSubmit,
  t,
}: {
  disabled: boolean
  onSubmit: (text: string) => void
  t: Dict
}) {
  const [text, setText] = useState("")
  return (
    <div className="flex gap-2">
      <input
        className={inputClass}
        placeholder={t.game.yourAnswer}
        value={text}
        disabled={disabled}
        onChange={(e) => setText(e.target.value)}
        onKeyDown={(e) => e.key === "Enter" && text.trim() && onSubmit(text)}
      />
      <Button disabled={disabled || !text.trim()} onClick={() => onSubmit(text)}>
        {t.game.validate}
      </Button>
    </div>
  )
}
