import { type CSSProperties, type FormEvent, useEffect, useMemo, useRef, useState } from 'react'
import { Navigate, useNavigate } from 'react-router-dom'
import { supabase } from '../lib/supabaseClient'
import { lighten, withAlpha } from '../features/song-select/color-utils'
import { type LetterGrade, letterGradeFromJudgments } from '../lib/judgmentGrade'
import { ROUTE_PATHS } from '../app/route-paths'
import { playSound, SFX_BUTTON_DEFAULT } from '../lib/sounds'
import { useGameStatsStore } from '../stores/game-stats/store'
import { useLeaderboardStore } from '../stores/leaderboard/store'
import styles from './EndOfGamePage.module.css'

export type { LetterGrade, GameEndState } from '../lib/judgmentGrade'

export type EndOfGamePageProps = {
  score?: number
  perfect?: number
  good?: number
  miss?: number
  /** Optional override; normally the grade is computed from judgment counts */
  grade?: LetterGrade | string
}

/** Arcade-style name length (one slot per character; increase if you need longer names) */
const ARCADE_NAME_MAX = 16

const DEFAULT_SCORE = 98500
const DEFAULT_PERFECT = 36
const DEFAULT_GOOD = 8
const DEFAULT_MISS = 1

const ACCENT_HEX = '#d946ef'

function gradeDataAttr(grade: string): 'S' | 'A' | 'B' | 'C' | 'D' | 'F' | 'other' {
  const g = grade.trim().toUpperCase().slice(0, 1)
  if (g === 'S' || g === 'A' || g === 'B' || g === 'C' || g === 'D' || g === 'F') {
    return g
  }
  return 'other'
}

function letterFromOverride(grade: string): LetterGrade {
  const g = grade.trim().toUpperCase().slice(0, 1)
  if (g === 'S' || g === 'A' || g === 'B' || g === 'C' || g === 'D' || g === 'F') {
    return g
  }
  return 'F'
}

function dominantJudgment(
  perfect: number,
  good: number,
  miss: number,
): 'perfect' | 'good' | 'miss' | null {
  const max = Math.max(perfect, good, miss)
  if (max === 0) return null
  if (perfect === max) return 'perfect'
  if (good === max) return 'good'
  return 'miss'
}

export function EndOfGamePage({
  score: scoreProp,
  perfect: perfectProp,
  good: goodProp,
  miss: missProp,
  grade: gradeProp,
}: EndOfGamePageProps) {
  const navigate = useNavigate()
  const nameInputRef = useRef<HTMLInputElement>(null)

  const currentSong = useGameStatsStore((state) => state.currentSong)
  const scoreStore = useGameStatsStore((state) => state.score)
  const perfectStore = useGameStatsStore((state) => state.perfectHits)
  const goodStore = useGameStatsStore((state) => state.goodHits)
  const missStore = useGameStatsStore((state) => state.misses)
  const gradeStore = useGameStatsStore((state) => state.computedGradeLetter)
  const setHighlight = useLeaderboardStore((state) => state.setHighlight)

  const hasStoreResults = currentSong != null || scoreStore > 0 || perfectStore + goodStore + missStore > 0

  if (!currentSong && !scoreProp) return <Navigate to={ROUTE_PATHS.intro} replace />

  const score = scoreProp ?? (hasStoreResults ? scoreStore : DEFAULT_SCORE)
  const perfect = perfectProp ?? (hasStoreResults ? perfectStore : DEFAULT_PERFECT)
  const good = goodProp ?? (hasStoreResults ? goodStore : DEFAULT_GOOD)
  const miss = missProp ?? (hasStoreResults ? missStore : DEFAULT_MISS)

  const gradeLetter = useMemo<LetterGrade>(() => {
    if (gradeProp !== undefined) return letterFromOverride(String(gradeProp))
    if (scoreProp === undefined && perfectProp === undefined && goodProp === undefined && missProp === undefined) {
      return gradeStore
    }
    return letterGradeFromJudgments(perfect, good, miss)
  }, [gradeProp, perfect, good, miss, gradeStore, scoreProp, perfectProp, goodProp, missProp])

  const gradeKey = gradeDataAttr(gradeLetter)

  const totalNotes = useMemo(() => perfect + good + miss, [perfect, good, miss])

  const judgmentLead = useMemo(
    () => dominantJudgment(perfect, good, miss),
    [perfect, good, miss],
  )

  const cssVars = useMemo(
    () =>
      ({
        '--endgame-accent': ACCENT_HEX,
        '--endgame-highlight': lighten(ACCENT_HEX, 0.42),
      }) as CSSProperties,
    [],
  )

  const summaryBarStyle = useMemo(
    () =>
      ({
        backgroundColor: withAlpha(ACCENT_HEX, 0.32),
        borderColor: withAlpha(ACCENT_HEX, 0.88),
      }) as CSSProperties,
    [],
  )

  const nameBarStyle = useMemo(
    () =>
      ({
        backgroundColor: withAlpha(ACCENT_HEX, 0.28),
        borderColor: withAlpha(ACCENT_HEX, 0.85),
      }) as CSSProperties,
    [],
  )

  const confirmBtnStyle = useMemo(
    () =>
      ({
        backgroundColor: lighten(ACCENT_HEX, 0.38),
        color: ACCENT_HEX,
      }) as CSSProperties,
    [],
  )

  const [displayScore, setDisplayScore] = useState(0)
  const [showGrade, setShowGrade] = useState(false)
  const [username, setUsername] = useState('')
  const [submitting, setSubmitting] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    let raf = 0
    let start: number | null = null
    const duration = 1500

    setShowGrade(false)

    const tick = (now: number) => {
      if (cancelled) return
      if (start === null) start = now
      const t = Math.min(1, (now - start) / duration)
      const eased = 1 - (1 - t) ** 3
      setDisplayScore(Math.round(score * eased))
      if (t >= 1) {
        if (!cancelled) {
          setDisplayScore(score)
          setShowGrade(true)
        }
        return
      }
      raf = requestAnimationFrame(tick)
    }

    raf = requestAnimationFrame(tick)
    return () => {
      cancelled = true
      cancelAnimationFrame(raf)
    }
  }, [score, gradeLetter])

  useEffect(() => {
    if (!showGrade) return
    const t = window.setTimeout(() => nameInputRef.current?.focus(), 520)
    return () => window.clearTimeout(t)
  }, [showGrade])

  function focusNameInput() {
    nameInputRef.current?.focus()
  }

  function handleNameChange(raw: string) {
    const upper = raw.toUpperCase().replace(/[^A-Z0-9\s\-_]/g, '')
    if (upper.length <= ARCADE_NAME_MAX) setUsername(upper)
  }

  async function handleSubmit(e: FormEvent) {
    e.preventDefault()
    setError(null)
    const trimmed = username.trim()
    if (!trimmed) {
      setError('Please enter a name.')
      return
    }

    setSubmitting(true)
    const { error: insertError } = await supabase.from('player_stats').insert({
      username: trimmed,
      highscore: score,
      grade: gradeLetter,
    })

    setSubmitting(false)

    if (insertError) {
      setError(insertError.message || 'Could not save your score.')
      return
    }

    setHighlight({ username: trimmed, score })

    navigate(ROUTE_PATHS.leaderboard)
  }

  function handleSkip() {
    navigate(ROUTE_PATHS.leaderboard)
  }

  return (
    <div className={styles.root} style={cssVars}>
      <div className={styles.hud} aria-hidden="true">
        <span className={`${styles.hudCorner} ${styles.hudCornerTl}`} />
        <span className={`${styles.hudCorner} ${styles.hudCornerTr}`} />
        <span className={`${styles.hudCorner} ${styles.hudCornerBl}`} />
        <span className={`${styles.hudCorner} ${styles.hudCornerBr}`} />
        <div className={styles.hudCounter}>RESULTS</div>
        <div className={styles.hudMetaLeft}>STAGE CLEAR</div>
        <div className={styles.hudMetaRight}>{showGrade ? `RANK ${gradeLetter}` : 'RANK —'}</div>
      </div>

      <div className={styles.inner}>
        <h1 className={`${styles.screenTitle} font-title`}>GAME OVER</h1>

        <section className={styles.scoreHero} aria-label="Final score">
          <span className={`${styles.scoreHeroLabel} font-caption`}>FINAL SCORE</span>
          <p className={`${styles.scoreHeroValue} font-display`}>{displayScore.toLocaleString()}</p>
        </section>

        {showGrade ? (
          <section className={styles.summaryBar} style={summaryBarStyle} aria-label="Grade and judgment">
            <div className={styles.summaryGradeCol}>
              <span className={`${styles.summaryStatLabel} font-caption`}>GRADE</span>
              <div
                className={`${styles.summaryGradeBadge} ${styles.gradeSlam}`}
                data-grade={gradeKey}
              >
                {gradeLetter}
              </div>
            </div>

            <div className={styles.summaryStats}>
              <div className={styles.summaryStat}>
                <span
                  className={`${styles.summaryStatNum} font-display ${styles.judgmentPerfect}${judgmentLead === 'perfect' ? ` ${styles.summaryStatLead}` : ''}`}
                >
                  {perfect}
                </span>
                <span className={`${styles.summaryStatLabel} font-caption`}>PERFECT</span>
              </div>
              <div className={styles.summaryStat}>
                <span
                  className={`${styles.summaryStatNum} font-display ${styles.judgmentGood}${judgmentLead === 'good' ? ` ${styles.summaryStatLead}` : ''}`}
                >
                  {good}
                </span>
                <span className={`${styles.summaryStatLabel} font-caption`}>GOOD</span>
              </div>
              <div className={styles.summaryStat}>
                <span
                  className={`${styles.summaryStatNum} font-display ${styles.judgmentMiss}${judgmentLead === 'miss' ? ` ${styles.summaryStatLead}` : ''}`}
                >
                  {miss}
                </span>
                <span className={`${styles.summaryStatLabel} font-caption`}>MISS</span>
              </div>
            </div>

            <p className={`${styles.summaryNotes} font-caption`}>
              {totalNotes} {totalNotes === 1 ? 'NOTE' : 'NOTES'}
            </p>
          </section>
        ) : null}

        <form className={styles.form} onSubmit={handleSubmit} noValidate>
          <section className={styles.nameBar} style={nameBarStyle}>
            <div className={styles.nameBarHeader}>
              <label className={`${styles.nameBarTitle} font-title`} htmlFor="arcade-name-input">
                ENTER YOUR NAME
              </label>
              <span className={`${styles.nameBarSub} font-caption`} id="arcade-name-hint">
                KEYBOARD · {ARCADE_NAME_MAX} CHARS MAX
              </span>
            </div>

            <input
              ref={nameInputRef}
              id="arcade-name-input"
              className={styles.nameInputHidden}
              type="text"
              name="username"
              autoComplete="off"
              autoCapitalize="characters"
              spellCheck={false}
              maxLength={ARCADE_NAME_MAX}
              value={username}
              onChange={(e) => handleNameChange(e.target.value)}
              aria-describedby="arcade-name-hint"
            />

            <div
              className={styles.nameSlots}
              role="presentation"
              onClick={focusNameInput}
              onKeyDown={(e) => {
                if (e.key === 'Enter' || e.key === ' ') {
                  e.preventDefault()
                  focusNameInput()
                }
              }}
              tabIndex={-1}
            >
              {Array.from({ length: ARCADE_NAME_MAX }).map((_, i) => {
                const ch = username[i]
                const showCaret = i === username.length && username.length < ARCADE_NAME_MAX
                return (
                  <span
                    key={i}
                    className={`${styles.nameSlot} font-display${showCaret ? ` ${styles.nameSlotActive}` : ''}`}
                  >
                    {ch ?? '\u00A0'}
                    {showCaret ? <span className={styles.nameCaret} /> : null}
                  </span>
                )
              })}
            </div>
          </section>

          <button
            type="submit"
            className={`${styles.arcadeConfirm} font-title`}
            style={confirmBtnStyle}
            disabled={submitting}
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
            }}
          >
            {submitting ? 'SAVING…' : 'SUBMIT SCORE'}
          </button>

          {error ? (
            <p className={styles.error} role="alert">
              {error}
            </p>
          ) : null}
        </form>

        <div className={styles.bottomActions}>
          <button
            type="button"
            className={`${styles.skip} font-caption`}
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              handleSkip()
            }}
          >
            SKIP TO LEADERBOARD
          </button>
          <button
            type="button"
            className={`${styles.skip} font-caption`}
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              navigate(ROUTE_PATHS.songSelection)
            }}
          >
            PLAY AGAIN
          </button>
          <button
            type="button"
            className={`${styles.skip} font-caption`}
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              navigate(ROUTE_PATHS.home)
            }}
          >
            HOME
          </button>
          <button
            type="button"
            className={`${styles.skip} font-caption`}
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              navigate(ROUTE_PATHS.credits)
            }}
          >
            CREDITS
          </button>
        </div>
      </div>
    </div>
  )
}
