import { useState, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { motion } from 'motion/react'
import { useFocusTrap } from '../hooks/useFocusTrap'
import { IconX, IconFlameFilled, IconChartAreaLineFilled,
         IconClockFilled, IconBulbFilled, IconPuzzleFilled,
         IconCircleArrowDownFilled, IconCircleArrowUpFilled,
         IconTrophyFilled, IconRosetteDiscountCheckFilled,
         IconStarFilled } from '@tabler/icons-react'
import * as api from '../api'

interface Summary {
  total_solves: number
  clean_solves: number
  total_time_secs: number
  avg_time_secs: number
  avg_hints: number
  current_streak: number
  best_streak: number
  first_solve: string | null
  puzzles_rated: number
  clues_submitted: number
}

interface SolveEntry {
  date: string
  preset: string
  time: number
  hints: number
}

interface TrendEntry {
  date: string
  avg_time?: number
  avg_hints?: number
}

interface PresetStats {
  count: number
  best: number
  avg: number
  clean: number
}

interface CleanRateEntry {
  date: string
  rate: number
}

interface MonthlyEntry {
  month: string
  count: number
}

interface DiffEntry {
  date: string
  avg_difficulty: number
}

interface FastestRecord {
  time: number
  date: string
}

interface Analytics {
  summary: Summary
  by_preset: Record<string, PresetStats>
  solve_history: SolveEntry[]
  activity_calendar: Record<string, number>
  by_hour: number[]
  by_day_of_week: number[]
  time_trend: TrendEntry[]
  hints_trend: TrendEntry[]
  improvement_rate: number | null
  clean_rate_trend: CleanRateEntry[]
  fastest_by_preset: Record<string, FastestRecord>
  solve_time_distribution: number[]
  monthly_totals: MonthlyEntry[]
  completion_rate: number
  words_encountered: number
  avg_time_by_hour: Record<string, number>
  difficulty_progression: DiffEntry[]
}

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

function fmtDate(d: string): string {
  const dt = new Date(d + 'T00:00:00')
  return dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
}

function fmtTotalTime(secs: number): string {
  if (secs < 60) return `${Math.round(secs)}s`
  if (secs < 3600) return `${Math.round(secs / 60)}m`
  const h = Math.floor(secs / 3600)
  const m = Math.round((secs % 3600) / 60)
  return m > 0 ? `${h}h ${m}m` : `${h}h`
}

function fmtMonth(m: string): string {
  const [, mo] = m.split('-')
  const names = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  return names[parseInt(mo, 10) - 1] || mo
}

// Catmull-Rom spline to SVG bezier path
function smoothPath(points: {x: number, y: number}[]): string {
  if (points.length < 2) return ''
  let d = `M ${points[0].x} ${points[0].y}`
  for (let i = 0; i < points.length - 1; i++) {
    const p0 = points[Math.max(i - 1, 0)]
    const p1 = points[i]
    const p2 = points[i + 1]
    const p3 = points[Math.min(i + 2, points.length - 1)]
    const cp1x = p1.x + (p2.x - p0.x) / 6
    const cp1y = p1.y + (p2.y - p0.y) / 6
    const cp2x = p2.x - (p3.x - p1.x) / 6
    const cp2y = p2.y - (p3.y - p1.y) / 6
    d += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`
  }
  return d
}

// smooth area path (closes to baseline)
function smoothArea(points: {x: number, y: number}[], baseline: number): string {
  if (points.length < 2) return ''
  const curve = smoothPath(points)
  return `${curve} L ${points[points.length - 1].x} ${baseline} L ${points[0].x} ${baseline} Z`
}

// SVG smooth line chart with area fill
function SmoothLineChart({ data, width, height, formatY, label, maxYOverride }: {
  data: { x: number; y: number; label?: string }[]
  width: number
  height: number
  formatY: (v: number) => string
  label?: string
  maxYOverride?: number
}) {
  if (data.length < 2) return null

  const pad = { top: 16, right: 8, bottom: 24, left: 42 }
  const w = width - pad.left - pad.right
  const h = height - pad.top - pad.bottom

  const minY = 0
  const maxY = maxYOverride || (Math.max(...data.map(d => d.y)) * 1.1 || 1)

  const pts = data.map((d, i) => ({
    x: pad.left + (i / (data.length - 1)) * w,
    y: pad.top + h - ((d.y - minY) / (maxY - minY)) * h,
    lbl: d.label,
  }))

  const curvePath = smoothPath(pts)
  const areaPath = smoothArea(pts, pad.top + h)

  const yTicks = 3
  const yLabels = Array.from({ length: yTicks + 1 }, (_, i) => {
    const val = minY + ((maxY - minY) / yTicks) * i
    return { val, y: pad.top + h - (i / yTicks) * h }
  })

  const gradId = `smooth-grad-${label || 'default'}`

  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`} className="analytics-chart-svg">
      {label && (
        <text x={pad.left} y={10} className="analytics-chart-label">{label}</text>
      )}
      {yLabels.map((yl, i) => (
        <g key={i}>
          <line x1={pad.left} y1={yl.y} x2={width - pad.right} y2={yl.y}
                stroke="var(--border)" strokeWidth={0.5} />
          <text x={pad.left - 6} y={yl.y + 3} textAnchor="end"
                className="analytics-chart-tick">{formatY(yl.val)}</text>
        </g>
      ))}
      <defs>
        <linearGradient id={gradId} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.2" />
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={areaPath} fill={`url(#${gradId})`} />
      <path d={curvePath} fill="none" stroke="var(--accent)" strokeWidth={1.5} />
      {pts.map((p, i) => (
        <circle key={i} cx={p.x} cy={p.y} r={2.5}
                fill="var(--bg)" stroke="var(--accent)" strokeWidth={1.5} />
      ))}
      {pts.filter((_, i) => i % Math.ceil(data.length / 6) === 0 || i === data.length - 1).map((p, i) => (
        <text key={i} x={p.x} y={pad.top + h + 14}
              textAnchor="middle" className="analytics-chart-tick">
          {p.lbl || ''}
        </text>
      ))}
    </svg>
  )
}

// SVG vertical bar chart
function BarChart({ data, labels, width, height, highlightMax, highlightMin, formatTooltip }: {
  data: number[]
  labels: string[]
  width: number
  height: number
  highlightMax?: boolean
  highlightMin?: boolean
  formatTooltip?: (v: number) => string
}) {
  if (!data.length) return null

  const pad = { top: 8, right: 4, bottom: 20, left: 4 }
  const w = width - pad.left - pad.right
  const h = height - pad.top - pad.bottom
  const maxVal = Math.max(...data) || 1
  const nonZero = data.filter(v => v > 0)
  const minNonZero = nonZero.length ? Math.min(...nonZero) : 0
  const peakIdx = highlightMax ? data.indexOf(maxVal) : -1
  const lowIdx = highlightMin && minNonZero > 0 ? data.indexOf(minNonZero) : -1
  const barW = Math.min(w / data.length * 0.7, 20)
  const gap = w / data.length

  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`} className="analytics-chart-svg">
      {data.map((val, i) => {
        const barH = (val / maxVal) * h
        const x = pad.left + i * gap + (gap - barW) / 2
        const y = pad.top + h - barH
        const isPeak = i === peakIdx && val > 0
        const isLow = i === lowIdx && val > 0
        return (
          <g key={i}>
            <rect x={x} y={y} width={barW} height={barH}
                  fill={isPeak ? 'var(--accent)' : isLow ? '#3b82f6' : 'var(--text)'}
                  opacity={isPeak || isLow ? 0.9 : 0.15} />
            {labels[i] && (
              <text x={x + barW / 2} y={pad.top + h + 13}
                    textAnchor="middle" className="analytics-chart-tick">
                {labels[i]}
              </text>
            )}
            {formatTooltip && val > 0 && (
              <title>{formatTooltip(val)}</title>
            )}
          </g>
        )
      })}
    </svg>
  )
}

// Histogram chart with labeled buckets
function Histogram({ buckets, minVal, maxVal, width, height }: {
  buckets: number[]
  minVal: number
  maxVal: number
  width: number
  height: number
}) {
  if (!buckets.length || buckets.every(b => b === 0)) return null

  const pad = { top: 8, right: 8, bottom: 28, left: 8 }
  const w = width - pad.left - pad.right
  const h = height - pad.top - pad.bottom
  const peak = Math.max(...buckets) || 1
  const bucketRange = (maxVal - minVal) / buckets.length
  const barW = (w / buckets.length) * 0.8
  const gap = w / buckets.length

  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`} className="analytics-chart-svg">
      {buckets.map((val, i) => {
        const barH = (val / peak) * h
        const x = pad.left + i * gap + (gap - barW) / 2
        const y = pad.top + h - barH
        const rangeStart = minVal + i * bucketRange
        const rangeEnd = rangeStart + bucketRange
        return (
          <g key={i}>
            <rect x={x} y={y} width={barW} height={Math.max(barH, 0)}
                  fill="var(--accent)" opacity={0.15 + (val / peak) * 0.65} />
            {i % 2 === 0 && (
              <text x={x + barW / 2} y={pad.top + h + 12}
                    textAnchor="middle" className="analytics-chart-tick">
                {fmtTime(Math.round(rangeStart))}
              </text>
            )}
            {val > 0 && (
              <text x={x + barW / 2} y={y - 3}
                    textAnchor="middle" className="analytics-chart-tick" style={{ fontSize: '5.5px' }}>
                {val}
              </text>
            )}
            <title>{fmtTime(Math.round(rangeStart))} - {fmtTime(Math.round(rangeEnd))}: {val} solve{val !== 1 ? 's' : ''}</title>
          </g>
        )
      })}
    </svg>
  )
}

// Donut/pie chart
function DonutChart({ segments, size }: {
  segments: { label: string; value: number; color: string }[]
  size: number
}) {
  const { t } = useTranslation()
  const total = segments.reduce((a, s) => a + s.value, 0)
  if (total === 0) return null

  const r = size / 2 - 4
  const cx = size / 2
  const cy = size / 2
  const strokeW = r * 0.35
  const innerR = r - strokeW / 2
  const circumference = 2 * Math.PI * innerR

  const arcs = segments.filter(s => s.value > 0).map((s, i, arr) => {
    const pct = s.value / total
    const dash = pct * circumference
    const offset = arr.slice(0, i).reduce((sum, prev) => sum + prev.value / total * circumference, 0)
    const rotation = offset / circumference * 360 - 90
    return { ...s, pct, dash, offset, rotation }
  })

  return (
    <div className="analytics-donut">
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        {arcs.map((a, i) => (
          <circle key={i} cx={cx} cy={cy} r={innerR}
                  fill="none" stroke={a.color} strokeWidth={strokeW}
                  strokeDasharray={`${a.dash} ${circumference - a.dash}`}
                  strokeDashoffset={-a.offset}
                  transform={`rotate(-90 ${cx} ${cy})`}>
            <title>{a.label}: {a.value} ({Math.round(a.pct * 100)}%)</title>
          </circle>
        ))}
        <text x={cx} y={cy - 4} textAnchor="middle"
              className="analytics-donut-total">{total}</text>
        <text x={cx} y={cy + 8} textAnchor="middle"
              className="analytics-donut-label">{t('analytics.total')}</text>
      </svg>
      <div className="analytics-donut-legend">
        {arcs.map((a, i) => (
          <div key={i} className="analytics-donut-legend-item">
            <span className="analytics-donut-swatch" style={{ background: a.color }} />
            <span className="analytics-donut-legend-name">{a.label}</span>
            <span className="analytics-donut-legend-val">{a.value}</span>
          </div>
        ))}
      </div>
    </div>
  )
}

// Semicircular gauge
function GaugeChart({ value, size }: { value: number; size: number }) {
  const { t } = useTranslation()
  const cx = size / 2
  const cy = size * 0.6
  const r = size * 0.4
  const startAngle = Math.PI
  const endAngle = 0
  const sweep = startAngle - endAngle
  const angle = startAngle - (value / 100) * sweep

  const arcPath = (start: number, end: number) => {
    const x1 = cx + r * Math.cos(start)
    const y1 = cy + r * Math.sin(start)
    const x2 = cx + r * Math.cos(end)
    const y2 = cy + r * Math.sin(end)
    const largeArc = Math.abs(end - start) > Math.PI ? 1 : 0
    return `M ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2}`
  }

  return (
    <div className="analytics-gauge">
      <svg width={size} height={size * 0.7} viewBox={`0 0 ${size} ${size * 0.7}`}>
        <path d={arcPath(startAngle, endAngle)} fill="none"
              stroke="var(--border)" strokeWidth={8} strokeLinecap="round" />
        {value > 0 && (
          <path d={arcPath(startAngle, angle)} fill="none"
                stroke="var(--accent)" strokeWidth={8} strokeLinecap="round" />
        )}
        <text x={cx} y={cy - 6} textAnchor="middle"
              className="analytics-gauge-value">{Math.round(value)}%</text>
        <text x={cx} y={cy + 8} textAnchor="middle"
              className="analytics-gauge-label">{t('analytics.completion')}</text>
      </svg>
    </div>
  )
}

// Activity heatmap
function ActivityHeatmap({ calendar }: { calendar: Record<string, number> }) {
  const { t } = useTranslation()
  const cellSize = 10
  const cellGap = 2
  const total = cellSize + cellGap

  const today = new Date()
  const days: { date: string; count: number; col: number; row: number }[] = []

  // build 365 days backwards
  for (let i = 364; i >= 0; i--) {
    const d = new Date(today)
    d.setDate(d.getDate() - i)
    const key = d.toISOString().split('T')[0]
    const dayOfWeek = (d.getDay() + 6) % 7 // Mon=0
    const daysFromEnd = i
    const col = 52 - Math.floor(daysFromEnd / 7)
    days.push({ date: key, count: calendar[key] || 0, col, row: dayOfWeek })
  }

  const totalSolves = Object.values(calendar).reduce((a, b) => a + b, 0)

  // month labels
  const months: { label: string; col: number }[] = []
  let lastMonth = -1
  for (const d of days) {
    const month = new Date(d.date + 'T00:00:00').getMonth()
    if (month !== lastMonth) {
      months.push({ label: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][month], col: d.col })
      lastMonth = month
    }
  }

  const dayLabels = ['Mo', '', 'We', '', 'Fr', '', '']
  const svgW = 53 * total + 24
  const svgH = 7 * total + 22

  function opacity(count: number): number {
    if (count === 0) return 0
    if (count === 1) return 0.2
    if (count <= 3) return 0.4
    if (count === 4) return 0.8
    return 1
  }

  return (
    <div>
      <svg width="100%" viewBox={`0 0 ${svgW} ${svgH}`} className="analytics-chart-svg">
        {months.map((m, i) => (
          <text key={i} x={24 + m.col * total} y={8}
                className="analytics-chart-tick">{m.label}</text>
        ))}
        {dayLabels.map((lbl, i) => (
          lbl ? <text key={i} x={18} y={16 + i * total + 8}
                      textAnchor="end" className="analytics-chart-tick">{lbl}</text> : null
        ))}
        {days.map((d, i) => (
          <rect key={i}
                x={24 + d.col * total} y={14 + d.row * total}
                width={cellSize} height={cellSize}
                fill={d.count > 0 ? 'var(--accent)' : 'var(--surface)'}
                opacity={d.count > 0 ? opacity(d.count) : 1}
                rx={1}>
            <title>{d.date}: {d.count} solve{d.count !== 1 ? 's' : ''}</title>
          </rect>
        ))}
      </svg>
      <div className="analytics-heatmap-total">
        {totalSolves !== 1 ? t('analytics.solvesInYear_plural', { count: totalSolves }) : t('analytics.solvesInYear', { count: totalSolves })}
      </div>
    </div>
  )
}

const presetOrder = ['glyph', 'rune', 'scroll', 'codex', 'grimoire']
const presetNames = {
  glyph: 'Glyph', rune: 'Rune', scroll: 'Scroll', codex: 'Codex', grimoire: 'Grimoire'
} satisfies Record<string, string>

function presetNameFor(names: Record<string, string>, key: string): string {
  return names[key] ?? key
}

export default function AnalyticsDashboard({ onClose }: { onClose: () => void }) {
  const trapRef = useFocusTrap(true)
  const { t } = useTranslation()
  const [data, setData] = useState<Analytics | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(false)

  useEffect(() => {
    api.fetchAnalytics()
      .then(d => { setData(d); setLoading(false) })
      .catch(() => { setError(true); setLoading(false) })
  }, [])

  useEffect(() => {
    function onKey(e: KeyboardEvent) { if (e.key === 'Escape') onClose() }
    document.addEventListener('keydown', onKey)
    return () => document.removeEventListener('keydown', onKey)
  }, [onClose])

  const timeTrendData = useMemo(() => {
    if (!data?.time_trend) return []
    return data.time_trend.map((t, i) => ({
      x: i, y: t.avg_time || 0, label: fmtDate(t.date)
    }))
  }, [data])

  const hintsTrendData = useMemo(() => {
    if (!data?.hints_trend) return []
    return data.hints_trend.map((t, i) => ({
      x: i, y: t.avg_hints || 0, label: fmtDate(t.date)
    }))
  }, [data])

  const cleanRateTrendData = useMemo(() => {
    if (!data?.clean_rate_trend?.length) return []
    return data.clean_rate_trend.map((t, i) => ({
      x: i, y: t.rate, label: fmtDate(t.date)
    }))
  }, [data])

  const diffProgressionData = useMemo(() => {
    if (!data?.difficulty_progression?.length) return []
    return data.difficulty_progression.map((t, i) => ({
      x: i, y: t.avg_difficulty, label: fmtDate(t.date)
    }))
  }, [data])

  const presetDonutData = useMemo(() => {
    if (!data?.by_preset) return []
    const colors = ['var(--accent)', 'color-mix(in srgb, var(--accent) 70%, var(--bg))', 'color-mix(in srgb, var(--accent) 50%, var(--bg))', 'color-mix(in srgb, var(--accent) 30%, var(--bg))', 'color-mix(in srgb, var(--accent) 15%, var(--bg))']
    return presetOrder
      .filter(k => data.by_preset[k]?.count > 0)
      .map((k, i) => ({
        label: presetNameFor(presetNames, k),
        value: data.by_preset[k].count,
        color: colors[i] || colors[colors.length - 1],
      }))
  }, [data])

  const avgTimeByHourData = useMemo(() => {
    if (!data?.avg_time_by_hour) return { data: [], labels: [] }
    const arr = Array.from({ length: 24 }, (_, i) => data.avg_time_by_hour[String(i)] || 0)
    const labels = Array.from({ length: 24 }, (_, i) => i % 3 === 0 ? String(i) : '')
    return { data: arr, labels }
  }, [data])

  // solve time distribution range
  const distRange = useMemo(() => {
    if (!data?.solve_history?.length) return { min: 0, max: 0 }
    const times = data.solve_history.map(s => s.time).filter(t => t > 0)
    if (!times.length) return { min: 0, max: 0 }
    return { min: Math.min(...times), max: Math.max(...times) }
  }, [data])

  const hourLabels = Array.from({ length: 24 }, (_, i) => i % 3 === 0 ? String(i) : '')
  // SAFETY: i18n's returnObjects contract returns an array for the dayNames key
  const dayLabels = t('analytics.dayNames', { returnObjects: true }) as string[]

  const presetMax = useMemo(() => {
    if (!data?.by_preset) return 1
    return Math.max(...presetOrder.map(k => data.by_preset[k]?.count || 0), 1)
  }, [data])

  const summary = data?.summary

  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="analytics-modal"
        onClick={e => e.stopPropagation()}
        role="dialog" aria-modal="true" aria-label={t('analytics.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] }}
      >
        {/* header */}
        <div className="analytics-header">
          <div className="analytics-title-row">
            <h3 className="analytics-title">
              <IconChartAreaLineFilled size={18} style={{ verticalAlign: -3, marginRight: 6 }} />
              {t('analytics.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>

        {loading && (
          <div className="analytics-empty">{t('common.loading')}</div>
        )}

        {error && (
          <div className="analytics-empty">{t('analytics.couldNotLoad')}</div>
        )}

        {data && summary && summary.total_solves === 0 && (
          <div className="analytics-empty">
            <IconPuzzleFilled size={32} style={{ color: 'var(--text-tertiary)', marginBottom: 8 }} />
            <div>{t('analytics.noPuzzlesSolved')}</div>
          </div>
        )}

        {data && summary && summary.total_solves > 0 && (
          <>
            {/* Row 1: summary cards (full width) */}
            <div className="analytics-section">
              <div className="analytics-cards">
                {[
                  { value: String(summary.total_solves), label: t('analytics.solved') },
                  { value: summary.total_solves > 0 ? Math.round((summary.clean_solves / summary.total_solves) * 100) + '%' : '0%', label: t('analytics.cleanRate') },
                  { value: fmtTotalTime(summary.total_time_secs), label: t('analytics.totalTime') },
                  { value: String(summary.current_streak), label: t('analytics.streak'), icon: true },
                  { value: String(summary.best_streak), label: t('analytics.bestStreak') },
                  { value: fmtTime(summary.avg_time_secs), label: t('analytics.avgTime') },
                ].map((card, i) => (
                  <motion.div
                    key={i}
                    className="analytics-card"
                    initial={{ opacity: 0, y: 8 }}
                    animate={{ opacity: 1, y: 0 }}
                    transition={{ delay: i * 0.05, duration: 0.25 }}
                  >
                    <div className="analytics-card-value">
                      {card.icon && <IconFlameFilled size={14} style={{ color: 'var(--accent)', verticalAlign: -2, marginRight: 2 }} />}
                      {card.value}
                    </div>
                    <div className="analytics-card-label">{card.label}</div>
                  </motion.div>
                ))}
              </div>
            </div>

            {/* Row 2: activity heatmap (full width) */}
            <motion.div className="analytics-section"
              initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
              transition={{ delay: 0.15, duration: 0.3 }}>
              <div className="analytics-section-title">{t('analytics.activity')}</div>
              <ActivityHeatmap calendar={data.activity_calendar || {}} />
            </motion.div>

            {/* Row 3: improvement + completion rate gauge - always render both */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.2, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.improvement')}</div>
                <div className="analytics-improvement" style={{ minHeight: '7rem', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
                  {data.improvement_rate != null ? (<>
                    <div className={`analytics-improvement-value ${data.improvement_rate <= 0 ? 'positive' : 'negative'}`}>
                      {data.improvement_rate <= 0 ? (
                        <IconCircleArrowDownFilled size={20} style={{ marginRight: 6 }} />
                      ) : (
                        <IconCircleArrowUpFilled size={20} style={{ marginRight: 6 }} />
                      )}
                      {Math.abs(data.improvement_rate).toFixed(1)}%
                    </div>
                    <div className="analytics-improvement-label">
                      {data.improvement_rate <= 0
                        ? t('analytics.fasterThanLastMonth', { pct: Math.abs(data.improvement_rate).toFixed(1) })
                        : t('analytics.slowerThanLastMonth', { pct: data.improvement_rate.toFixed(1) })}
                    </div>
                  </>) : (
                    <div className="analytics-mini-stat">
                      <span className="analytics-mini-val">-</span>
                      <span className="analytics-mini-label">{t('analytics.needMoreSolves')}</span>
                    </div>
                  )}
                </div>
              </motion.div>
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.25, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.completionRate')}</div>
                <GaugeChart value={data.completion_rate || 0} size={160} />
              </motion.div>
            </div>

            {/* Row 4: solve time trend (full width) */}
            {timeTrendData.length >= 2 && (
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.3, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.solveTimeTrend')}</div>
                <SmoothLineChart data={timeTrendData} width={560} height={140}
                           formatY={v => fmtTime(Math.round(v))} label="time" />
              </motion.div>
            )}

            {/* Row 5: time of day + consistency+day stacked - always render both */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.35, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.timeOfDay')}</div>
                <BarChart data={data.by_hour || Array(24).fill(0)} labels={hourLabels}
                          width={280} height={100} highlightMax />
              </motion.div>
              <div className="analytics-stacked">
                <motion.div className="analytics-section analytics-section-compact"
                  initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                  transition={{ delay: 0.38, duration: 0.3 }}>
                  <div className="analytics-section-title">{t('analytics.consistency')}</div>
                  {(() => {
                    const times = (data.solve_history || []).map(s => s.time).filter(t => t > 0)
                    if (times.length < 2) return <div className="analytics-mini-stat"><span className="analytics-mini-val">-</span><span className="analytics-mini-label">{t('analytics.notEnoughData')}</span></div>
                    const avg = times.reduce((a, b) => a + b, 0) / times.length
                    const variance = times.reduce((a, t) => a + Math.pow(t - avg, 2), 0) / times.length
                    const stdDev = Math.sqrt(variance)
                    const cv = (stdDev / avg) * 100
                    const rating = cv < 15 ? t('analytics.veryConsistent') : cv < 30 ? t('analytics.consistent') : cv < 50 ? t('analytics.variable') : t('analytics.unpredictable')
                    return (
                      <div className="analytics-mini-stat">
                        <span className="analytics-mini-val">{Math.round(cv)}%</span>
                        <span className="analytics-mini-label">{t('analytics.variance')} - {rating}</span>
                      </div>
                    )
                  })()}
                </motion.div>
                <motion.div className="analytics-section analytics-section-compact"
                  initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                  transition={{ delay: 0.4, duration: 0.3 }}>
                  <div className="analytics-section-title">{t('analytics.dayOfWeek')}</div>
                  <BarChart data={data.by_day_of_week || Array(7).fill(0)} labels={dayLabels}
                            width={280} height={80} highlightMax />
                </motion.div>
              </div>
            </div>

            {/* Row 6: preset breakdown + preset donut */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                  initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                  transition={{ delay: 0.45, duration: 0.3 }}>
                  <div className="analytics-section-title">{t('analytics.byPreset')}</div>
                  <div className="analytics-presets">
                    {presetOrder.filter(k => data.by_preset[k]).map((k, i) => {
                      const p = data.by_preset[k]
                      const pct = (p.count / presetMax) * 100
                      const opacities = [0.9, 0.7, 0.5, 0.35, 0.2]
                      return (
                        <div key={k} className="analytics-preset-row">
                          <span className="analytics-preset-name">{presetNameFor(presetNames, k)}</span>
                          <div className="analytics-preset-bar-wrap">
                            <div className="analytics-preset-bar"
                                 style={{ width: `${Math.max(pct, 2)}%`, opacity: opacities[i] || 0.5 }} />
                          </div>
                          <span className="analytics-preset-count">{p.count}</span>
                          <span className="analytics-preset-best">best {fmtTime(p.best)}</span>
                        </div>
                      )
                    })}
                  </div>
                </motion.div>
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.5, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.presetMix')}</div>
                <div style={{ display: 'flex', justifyContent: 'center' }}>
                  {presetDonutData.length > 0
                    ? <DonutChart segments={presetDonutData} size={160} />
                    : <div className="analytics-mini-stat"><span className="analytics-mini-label">{t('analytics.notEnoughDataYet')}</span></div>}
                </div>
              </motion.div>
            </div>

            {/* Row 7: hints trend + clean solve trend */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.55, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.hintsTrend')}</div>
                {hintsTrendData.length >= 2
                  ? <SmoothLineChart data={hintsTrendData} width={280} height={140} formatY={v => v.toFixed(1)} label="hints" />
                  : <div className="analytics-mini-stat"><span className="analytics-mini-label">{t('analytics.notEnoughDataYet')}</span></div>}
              </motion.div>
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.6, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.cleanSolveTrend')}</div>
                {cleanRateTrendData.length >= 2
                  ? <SmoothLineChart data={cleanRateTrendData} width={280} height={140} formatY={v => `${Math.round(v)}%`} label="clean" maxYOverride={100} />
                  : <div className="analytics-mini-stat"><span className="analytics-mini-label">{t('analytics.notEnoughDataYet')}</span></div>}
              </motion.div>
            </div>

            {/* Row 8: monthly volume + solve time distribution - always both */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.65, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.monthlyVolume')}</div>
                {data.monthly_totals && data.monthly_totals.length > 0
                  ? <BarChart data={data.monthly_totals.map(m => m.count)} labels={data.monthly_totals.map(m => fmtMonth(m.month))} width={280} height={120} highlightMax />
                  : <div className="analytics-mini-stat"><span className="analytics-mini-label">{t('analytics.notEnoughDataYet')}</span></div>}
              </motion.div>
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.7, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.solveTimeDistribution')}</div>
                {data.solve_time_distribution && data.solve_time_distribution.some(v => v > 0)
                  ? <Histogram buckets={data.solve_time_distribution} minVal={distRange.min} maxVal={distRange.max} width={280} height={120} />
                  : <div className="analytics-mini-stat"><span className="analytics-mini-label">{t('analytics.notEnoughDataYet')}</span></div>}
              </motion.div>
            </div>

            {/* Row 9: difficulty progression (full width) */}
            {diffProgressionData.length >= 2 && (
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.75, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.difficultyProgression')}</div>
                <SmoothLineChart data={diffProgressionData} width={560} height={140}
                           formatY={v => {
                             const names = ['Glyph','Rune','Scroll','Codex','Grimoire']
                             const idx = Math.round(v)
                             return names[Math.min(idx, 4)] || ''
                           }}
                           label="difficulty" maxYOverride={4.5} />
              </motion.div>
            )}

            {/* Row 10: peak performance + streak progress - always both */}
            <div className="analytics-grid-2">
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.8, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.peakPerformance')}</div>
                  <div className="analytics-peak-hint">
                    {(() => {
                      const nonZero = avgTimeByHourData.data
                        .map((v, i) => ({ v, i }))
                        .filter(x => x.v > 0)
                      if (!nonZero.length) return null
                      const best = nonZero.reduce((a, b) => a.v < b.v ? a : b)
                      return (
                        <span>
                          <IconStarFilled size={12} style={{ verticalAlign: -2, marginRight: 4, color: 'var(--accent)' }} />
                          {t('analytics.fastestAt', { hour: best.i, time: fmtTime(best.v) })}
                        </span>
                      )
                    })()}
                  </div>
                  <BarChart
                    data={avgTimeByHourData.data}
                    labels={avgTimeByHourData.labels}
                    width={280} height={100}
                    highlightMin
                    formatTooltip={v => `avg ${fmtTime(v)}`}
                  />
                </motion.div>
              <motion.div className="analytics-section"
                  initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                  transition={{ delay: 0.85, duration: 0.3 }}>
                  <div className="analytics-section-title">{t('analytics.streakProgress')}</div>
                  <div className="analytics-streak-bar">
                    <div className="analytics-streak-track">
                      <div className="analytics-streak-fill"
                           style={{ width: `${Math.min((summary.current_streak / summary.best_streak) * 100, 100)}%` }} />
                    </div>
                    <div className="analytics-streak-labels">
                      <span>
                        <IconFlameFilled size={11} style={{ verticalAlign: -2, marginRight: 3, color: 'var(--accent)' }} />
                        {summary.current_streak !== 1 ? t('analytics.daysCurrent_plural', { count: summary.current_streak }) : t('analytics.daysCurrent', { count: summary.current_streak })}
                      </span>
                      <span>
                        <IconRosetteDiscountCheckFilled size={11} style={{ verticalAlign: -2, marginRight: 3 }} />
                        {summary.best_streak !== 1 ? t('analytics.daysBest_plural', { count: summary.best_streak }) : t('analytics.daysBest', { count: summary.best_streak })}
                      </span>
                    </div>
                    {summary.current_streak >= summary.best_streak && summary.current_streak > 0 && (
                      <div className="analytics-streak-record">
                        <IconStarFilled size={12} style={{ verticalAlign: -2, marginRight: 4 }} />
                        {t('analytics.bestStreakNow')}
                      </div>
                    )}
                  </div>
                </motion.div>
            </div>

            {/* Row 11: personal records (full width) */}
            {data.fastest_by_preset && Object.keys(data.fastest_by_preset).length > 0 && (
              <motion.div className="analytics-section"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.9, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.personalRecords')}</div>
                <div className="analytics-record-cards">
                  {presetOrder.filter(k => data.fastest_by_preset[k]).map((k, i) => (
                    <motion.div key={k} className="analytics-record-card"
                      initial={{ opacity: 0, y: 6 }}
                      animate={{ opacity: 1, y: 0 }}
                      transition={{ delay: 0.9 + i * 0.05, duration: 0.2 }}>
                      <div className="analytics-record-icon">
                        <IconTrophyFilled size={14} />
                      </div>
                      <div className="analytics-record-preset">{presetNameFor(presetNames, k)}</div>
                      <div className="analytics-record-time">{fmtTime(data.fastest_by_preset[k].time)}</div>
                      <div className="analytics-record-date">{fmtDate(data.fastest_by_preset[k].date)}</div>
                    </motion.div>
                  ))}
                </div>
              </motion.div>
            )}

            {/* Row 12: recent solves (full width) */}
            {data.solve_history && data.solve_history.length > 0 && (
              <motion.div className="analytics-section analytics-section-last"
                initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.95, duration: 0.3 }}>
                <div className="analytics-section-title">{t('analytics.recentSolves')}</div>
                <div className="analytics-recent">
                  {data.solve_history.slice(0, 20).map((s, i) => (
                    <div key={i} className="analytics-recent-row">
                      <span className="analytics-recent-date">{fmtDate(s.date)}</span>
                      <span className="analytics-recent-preset">{presetNameFor(presetNames, s.preset)}</span>
                      <span className="analytics-recent-time">
                        <IconClockFilled size={10} /> {fmtTime(s.time)}
                      </span>
                      {s.hints > 0 && (
                        <span className="analytics-recent-hints">
                          <IconBulbFilled size={10} /> {s.hints}
                        </span>
                      )}
                    </div>
                  ))}
                </div>
              </motion.div>
            )}
          </>
        )}
      </motion.div>
    </motion.div>
  )
}
