import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { IconClockFilled, IconBulbFilled, IconWorldFilled,
         IconAwardFilled, IconRosetteDiscountCheckFilled, IconX, IconCrownFilled,
         IconFlameFilled, IconTrophyFilled } from '@tabler/icons-react'
import { motion, AnimatePresence } from 'motion/react'
import * as api from '../api'
import type { LeaderboardEntry } from '../api'
import DatePicker from './ui/DatePicker'
import { useFocusTrap } from '../hooks/useFocusTrap'

type Tab = 'daily' | 'alltime' | 'weekly' | 'streaks' | 'total' | 'global'

type LocalEntry = LeaderboardEntry
type FederatedEntry = LeaderboardEntry
type StreakEntry = LeaderboardEntry
type CompletionistEntry = LeaderboardEntry

function formatTime(secs: number) {
  if (secs <= 0) return '--:--'
  const m = Math.floor(secs / 60)
  const s = secs % 60
  return `${m}:${s.toString().padStart(2, '0')}`
}

function RankBadge({ rank }: { rank: number }) {
  if (rank === 1) return <span aria-label="1st place"><IconCrownFilled size={14} style={{ color: '#eab308' }} /></span>
  if (rank === 2) return <span aria-label="2nd place"><IconAwardFilled size={14} style={{ color: '#94a3b8' }} /></span>
  if (rank === 3) return <span aria-label="3rd place"><IconRosetteDiscountCheckFilled size={14} style={{ color: '#b45309' }} /></span>
  return <span className="lb-rank-num">{rank}</span>
}

const PRESETS = [
  { id: 'glyph', name: 'Glyph' },
  { id: 'rune', name: 'Rune' },
  { id: 'scroll', name: 'Scroll' },
  { id: 'codex', name: 'Codex' },
  { id: 'grimoire', name: 'Grimoire' },
]

const TAB_IDS: { id: Tab; icon?: typeof IconWorldFilled }[] = [
  { id: 'daily' },
  { id: 'alltime' },
  { id: 'weekly' },
  { id: 'streaks', icon: IconFlameFilled },
  { id: 'total', icon: IconTrophyFilled },
  { id: 'global', icon: IconWorldFilled },
]

const SLOTS = 10

const showPresets = (tab: Tab) => tab !== 'streaks' && tab !== 'total'
const showCleanToggle = (tab: Tab) => tab === 'daily' || tab === 'alltime' || tab === 'weekly'

export default function DailyLeaderboard({ onClose }: { onClose: () => void }) {
  const trapRef = useFocusTrap(true)
  const { t } = useTranslation()
  const [tab, setTab] = useState<Tab>('daily')
  const [preset, setPreset] = useState('scroll')
  const [date, setDate] = useState(() => new Date().toISOString().split('T')[0])
  const [cleanOnly, setCleanOnly] = useState(false)
  const [loading, setLoading] = useState(false)

  const [localEntries, setLocalEntries] = useState<LocalEntry[]>([])
  const [globalEntries, setGlobalEntries] = useState<FederatedEntry[]>([])
  const [streakEntries, setStreakEntries] = useState<StreakEntry[]>([])
  const [completionistEntries, setCompletionistEntries] = useState<CompletionistEntry[]>([])

  useEffect(() => {
    let cancelled = false
    const done = () => { if (!cancelled) setLoading(false) }
    const clear = () => {
      setLocalEntries([]); setGlobalEntries([])
      setStreakEntries([]); setCompletionistEntries([])
    }

    queueMicrotask(() => { if (!cancelled) { setLoading(true); clear() } })

    if (tab === 'daily') {
      const fn = cleanOnly ? api.fetchCleanLeaderboard : api.fetchDailyLeaderboard
      fn(date, preset)
        .then(d => { if (!cancelled) setLocalEntries(d.entries || []) })
        .catch(() => {})
        .finally(done)
    } else if (tab === 'alltime') {
      api.fetchAlltimeLeaderboard(preset)
        .then(d => { if (!cancelled) setLocalEntries(d.entries || []) })
        .catch(() => {})
        .finally(done)
    } else if (tab === 'weekly') {
      if (cleanOnly) {
        api.fetchCleanLeaderboard(date, preset)
          .then(d => { if (!cancelled) setLocalEntries(d.entries || []) })
          .catch(() => {})
          .finally(done)
      } else {
        api.fetchWeeklyLeaderboard(preset)
          .then(d => { if (!cancelled) setLocalEntries(d.entries || []) })
          .catch(() => {})
          .finally(done)
      }
    } else if (tab === 'streaks') {
      api.fetchStreakLeaderboard()
        .then(d => { if (!cancelled) setStreakEntries(d.entries || []) })
        .catch(() => {})
        .finally(done)
    } else if (tab === 'total') {
      api.fetchCompletionistLeaderboard()
        .then(d => { if (!cancelled) setCompletionistEntries(d.entries || []) })
        .catch(() => {})
        .finally(done)
    } else if (tab === 'global') {
      api.fetchFederatedLeaderboard(date, preset)
        .then(d => { if (!cancelled) setGlobalEntries(d.entries || []) })
        .catch(() => {})
        .finally(done)
    }

    return () => { cancelled = true }
  }, [tab, preset, date, cleanOnly])

  const renderHeader = () => {
    if (tab === 'streaks') {
      return (
        <div className="lb-table-header" role="row">
          <span className="lb-col-rank" role="columnheader">{t('leaderboard.columns.rank')}</span>
          <span className="lb-col-name" role="columnheader">{t('leaderboard.columns.player')}</span>
          <span className="lb-col-time" role="columnheader">{t('leaderboard.columns.current')}</span>
          <span className="lb-col-hints" role="columnheader">{t('leaderboard.columns.best')}</span>
        </div>
      )
    }
    if (tab === 'total') {
      return (
        <div className="lb-table-header" role="row">
          <span className="lb-col-rank" role="columnheader">{t('leaderboard.columns.rank')}</span>
          <span className="lb-col-name" role="columnheader">{t('leaderboard.columns.player')}</span>
          <span className="lb-col-time" role="columnheader">{t('leaderboard.columns.solves')}</span>
        </div>
      )
    }
    if (tab === 'global') {
      return (
        <div className="lb-table-header" role="row">
          <span className="lb-col-rank" role="columnheader">{t('leaderboard.columns.rank')}</span>
          <span className="lb-col-name" role="columnheader">{t('leaderboard.columns.player')}</span>
          <span className="lb-col-instance" role="columnheader">{t('leaderboard.columns.instance')}</span>
          <span className="lb-col-time" role="columnheader">{t('leaderboard.columns.time')}</span>
        </div>
      )
    }
    // daily, alltime, weekly
    return (
      <div className="lb-table-header" role="row">
        <span className="lb-col-rank" role="columnheader">{t('leaderboard.columns.rank')}</span>
        <span className="lb-col-name" role="columnheader">{t('leaderboard.columns.player')}</span>
        <span className="lb-col-time" role="columnheader">{t('leaderboard.columns.time')}</span>
        <span className="lb-col-hints" role="columnheader">{t('leaderboard.columns.hints')}</span>
        {tab === 'alltime' && <span className="lb-col-date" role="columnheader">{t('leaderboard.columns.date')}</span>}
      </div>
    )
  }

  const renderRow = (i: number) => {
    const rank = i + 1

    if (tab === 'streaks') {
      const entry = streakEntries[i]
      return (
        <div key={i} className={`lb-row ${entry && rank <= 3 ? 'lb-row-top' : ''} ${!entry ? 'lb-row-empty' : ''}`} role="row">
          <span className="lb-col-rank" role="cell">
            {entry ? <RankBadge rank={rank} /> : <span className="lb-rank-num lb-rank-dim">{rank}</span>}
          </span>
          <span className="lb-col-name" role="cell">
            {entry ? entry.name || t('common.anonymous') : <span className="lb-empty-dash">-</span>}
          </span>
          <span className="lb-col-time" role="cell">
            {entry ? (
              <><IconFlameFilled size={10} aria-hidden="true" /> {entry.current}</>
            ) : <span className="lb-empty-dash">-</span>}
          </span>
          <span className="lb-col-hints" role="cell">
            {entry ? entry.best : ''}
          </span>
        </div>
      )
    }

    if (tab === 'total') {
      const entry = completionistEntries[i]
      return (
        <div key={i} className={`lb-row ${entry && rank <= 3 ? 'lb-row-top' : ''} ${!entry ? 'lb-row-empty' : ''}`} role="row">
          <span className="lb-col-rank" role="cell">
            {entry ? <RankBadge rank={rank} /> : <span className="lb-rank-num lb-rank-dim">{rank}</span>}
          </span>
          <span className="lb-col-name" role="cell">
            {entry ? entry.name || t('common.anonymous') : <span className="lb-empty-dash">-</span>}
          </span>
          <span className="lb-col-time" role="cell">
            {entry ? entry.count : <span className="lb-empty-dash">-</span>}
          </span>
        </div>
      )
    }

    if (tab === 'global') {
      const entry = globalEntries[i]
      return (
        <div key={i} className={`lb-row ${entry && rank <= 3 ? 'lb-row-top' : ''} ${!entry ? 'lb-row-empty' : ''}`} role="row">
          <span className="lb-col-rank" role="cell">
            {entry ? <RankBadge rank={rank} /> : <span className="lb-rank-num lb-rank-dim">{rank}</span>}
          </span>
          <span className="lb-col-name" role="cell">
            {entry ? entry.name || t('common.anonymous') : <span className="lb-empty-dash">-</span>}
          </span>
          <span className="lb-col-instance" role="cell">
            {entry?.instance || ''}
          </span>
          <span className="lb-col-time" role="cell">
            {entry ? (
              <><IconClockFilled size={10} aria-hidden="true" /> {formatTime(entry.time)}</>
            ) : <span className="lb-empty-dash">--:--</span>}
          </span>
        </div>
      )
    }

    // daily, alltime, weekly
    const entry = localEntries[i]
    return (
      <div key={i} className={`lb-row ${entry && rank <= 3 ? 'lb-row-top' : ''} ${!entry ? 'lb-row-empty' : ''}`} role="row">
        <span className="lb-col-rank" role="cell">
          {entry ? <RankBadge rank={rank} /> : <span className="lb-rank-num lb-rank-dim">{rank}</span>}
        </span>
        <span className="lb-col-name" role="cell">
          {entry ? entry.name || t('common.anonymous') : <span className="lb-empty-dash">-</span>}
        </span>
        <span className="lb-col-time" role="cell">
          {entry ? (
            <><IconClockFilled size={10} aria-hidden="true" /> {formatTime(entry.time)}</>
          ) : <span className="lb-empty-dash">--:--</span>}
        </span>
        <span className="lb-col-hints" role="cell">
          {entry && entry.hints > 0 ? (
            <><IconBulbFilled size={9} aria-hidden="true" /> {entry.hints}</>
          ) : ''}
        </span>
        {tab === 'alltime' && (
          <span className="lb-col-date" role="cell">
            {entry?.date || ''}
          </span>
        )}
      </div>
    )
  }

  return (
    <motion.div
      className="settings-overlay"
      onClick={onClose}
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 0.15 }}
    >
      <motion.div
        ref={trapRef}
        className="lb-modal"
        onClick={e => e.stopPropagation()}
        role="dialog" aria-modal="true" aria-label={t('leaderboard.title')}
        initial={{ opacity: 0, scale: 0.95, y: 12 }}
        animate={{ opacity: 1, scale: 1, y: 0 }}
        exit={{ opacity: 0, scale: 0.95, y: 12 }}
        transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
      >
        <div className="lb-top">
          <div className="lb-title-row">
            <h3 className="lb-title">{t('leaderboard.title')}</h3>
            <button className="btn btn-sm btn-ghost" onClick={onClose} aria-label={t('common.close')}><IconX size={16} aria-hidden="true" /></button>
          </div>
        </div>

        <div className="lb-controls">
          <div className="lb-tabs" role="tablist">
            {TAB_IDS.map(tb => (
              <button key={tb.id}
                className={`lb-tab ${tab === tb.id ? 'lb-tab-active' : ''}`}
                onClick={() => setTab(tb.id)}
                role="tab"
                aria-selected={tab === tb.id}
                aria-controls="lb-tabpanel"
                id={`lb-tab-${tb.id}`}>
                {tb.icon && <tb.icon size={9} style={{ marginRight: 3, verticalAlign: -1 }} aria-hidden="true" />}
                {t(`leaderboard.tabs.${tb.id}`)}
              </button>
            ))}
          </div>

          {showPresets(tab) && (
            <div className="lb-presets">
              {PRESETS.map(p => (
                <button key={p.id}
                  className={`lb-preset ${preset === p.id ? 'lb-preset-active' : ''}`}
                  onClick={() => setPreset(p.id)}>
                  {p.name}
                </button>
              ))}
              {tab === 'daily' && (
                <DatePicker value={date} onChange={setDate} />
              )}
            </div>
          )}

          {showCleanToggle(tab) && (
            <label className="lb-clean-toggle">
              <input type="checkbox" checked={cleanOnly} onChange={e => setCleanOnly(e.target.checked)} />
              {t('leaderboard.cleanOnly')}
            </label>
          )}
        </div>

        <div className="lb-table" role="tabpanel" id="lb-tabpanel" aria-labelledby={`lb-tab-${tab}`}>
          <AnimatePresence mode="wait">
            <motion.div
              key={`${tab}-${preset}-${date}-${cleanOnly}`}
              role="table"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.15 }}
            >
              {renderHeader()}
              {Array.from({ length: SLOTS }, (_, i) => renderRow(i))}
            </motion.div>
          </AnimatePresence>

          <AnimatePresence>
            {loading && (
              <motion.div className="lb-loading" key="lb-load"
                initial={{ opacity: 0 }} animate={{ opacity: 1 }}
                exit={{ opacity: 0 }} transition={{ duration: 0.15 }}>
                <div className="spinner" style={{ width: 16, height: 16 }} />
              </motion.div>
            )}
          </AnimatePresence>
        </div>
      </motion.div>
    </motion.div>
  )
}
