// frontend\src\components\ui\FinishedReportModal.tsx

'use client'

import { useCallback, useEffect, useMemo, useState, type ReactNode } from 'react'
import {
  ArchiveBoxIcon,
  ArrowPathIcon,
  CalendarDaysIcon,
  ChartBarIcon,
  ClockIcon,
  FireIcon,
  StarIcon,
} from '@heroicons/react/24/outline'

import type {
  FinishedReportDailyItem,
  FinishedReportMode,
  FinishedReportStats,
  FinishedReportTopItem,
  RecordJob,
} from '../../types'
import Modal from './Modal'
import Button from './Button'
import ButtonGroup from './ButtonGroup'
import LoadingSpinner from './LoadingSpinner'
import { autoTagsForJob, ratingStarsForJob } from './autoTags'
import { SegmentLabelIcon } from './Icons'

const REPORT_PAGE_SIZE = 1000

const nf = new Intl.NumberFormat('de-DE')

function fmtInt(value: number | undefined | null) {
  if (value == null || !Number.isFinite(value)) return '—'
  return nf.format(value)
}

function fmtBytes(value: number | undefined | null) {
  if (value == null || !Number.isFinite(value)) return '—'

  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let v = value
  let i = 0

  while (v >= 1024 && i < units.length - 1) {
    v /= 1024
    i++
  }

  const digits = i <= 1 ? 0 : 1
  return `${v.toFixed(digits)} ${units[i]}`
}

function fmtDuration(totalSeconds: number | undefined | null) {
  if (totalSeconds == null || !Number.isFinite(totalSeconds) || totalSeconds <= 0) {
    return '—'
  }

  const s = Math.floor(totalSeconds)
  const h = Math.floor(s / 3600)
  const m = Math.floor((s % 3600) / 60)
  const sec = s % 60

  if (h > 0) {
    return `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`
  }

  return `${m}:${String(sec).padStart(2, '0')}`
}

function parseMeta(metaRaw: unknown): Record<string, any> | null {
  if (!metaRaw) return null

  if (typeof metaRaw === 'string') {
    try {
      const parsed = JSON.parse(metaRaw)
      return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
        ? parsed as Record<string, any>
        : null
    } catch {
      return null
    }
  }

  return typeof metaRaw === 'object' && !Array.isArray(metaRaw)
    ? metaRaw as Record<string, any>
    : null
}

function readNumberLike(...values: unknown[]): number | null {
  for (const value of values) {
    const n = Number(value)
    if (Number.isFinite(n) && n > 0) return n
  }

  return null
}

function readJobDurationSeconds(job: RecordJob): number | null {
  const meta = parseMeta((job as any)?.meta)

  return readNumberLike(
    (job as any)?.durationSeconds,
    (job as any)?.durationSec,
    meta?.media?.durationSeconds,
    meta?.media?.durationSec,
    meta?.file?.durationSeconds,
    meta?.file?.durationSec,
    meta?.durationSeconds,
    meta?.durationSec
  )
}

function readJobSizeBytes(job: RecordJob): number | null {
  const meta = parseMeta((job as any)?.meta)

  return readNumberLike(
    (job as any)?.sizeBytes,
    (job as any)?.fileSizeBytes,
    (job as any)?.bytes,
    (job as any)?.size,
    meta?.file?.sizeBytes,
    meta?.file?.bytes,
    meta?.sizeBytes,
    meta?.bytes,
    meta?.size
  )
}

function baseName(path: string) {
  return String(path || '').split(/[\\/]/).pop() || ''
}

function stripHotPrefix(name: string) {
  return String(name || '').startsWith('HOT ')
    ? String(name || '').slice(4)
    : String(name || '')
}

function isHotOutput(output: string) {
  return baseName(output).startsWith('HOT ')
}

function isKeepOutput(output: string) {
  return String(output || '').replaceAll('\\', '/').includes('/keep/')
}

function modelNameFromOutput(output?: string) {
  const fileRaw = baseName(output || '')
  const file = stripHotPrefix(fileRaw)
  if (!file) return '—'

  const stem = file.replace(/\.[^.]+$/, '')

  const m = stem.match(/^(.*?)_\d{1,2}_\d{1,2}_\d{4}__\d{1,2}-\d{2}-\d{2}$/)
  if (m?.[1]) return m[1]

  const i = stem.lastIndexOf('_')
  return i > 0 ? stem.slice(0, i) : stem
}

function readJobDate(job: RecordJob): Date | null {
  const raw =
    (job as any)?.endedAt ??
    (job as any)?.completedAt ??
    (job as any)?.startedAt ??
    null

  if (!raw) return null

  const d = new Date(raw)
  return Number.isFinite(d.getTime()) ? d : null
}

function startOfDay(value: Date) {
  const d = new Date(value)
  d.setHours(0, 0, 0, 0)
  return d
}

function addDays(value: Date, days: number) {
  const d = new Date(value)
  d.setDate(d.getDate() + days)
  return d
}

function startOfWeekMonday(value: Date) {
  const d = startOfDay(value)
  const day = d.getDay()
  const diff = day === 0 ? -6 : 1 - day
  d.setDate(d.getDate() + diff)
  return d
}

function reportPeriod(mode: FinishedReportMode, now = new Date()) {
  if (mode === 'week') {
    const start = startOfWeekMonday(now)
    return {
      start,
      end: addDays(start, 7),
    }
  }

  const start = startOfDay(now)
  return {
    start,
    end: addDays(start, 1),
  }
}

function dateKey(value: Date) {
  return [
    value.getFullYear(),
    String(value.getMonth() + 1).padStart(2, '0'),
    String(value.getDate()).padStart(2, '0'),
  ].join('-')
}

function shortDateLabel(value: Date) {
  return value.toLocaleDateString('de-DE', {
    weekday: 'short',
    day: '2-digit',
    month: '2-digit',
  })
}

function longDateLabel(value: Date) {
  return value.toLocaleDateString('de-DE', {
    weekday: 'long',
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  })
}

function rangeLabel(start: Date, end: Date) {
  const last = addDays(end, -1)

  if (dateKey(start) === dateKey(last)) {
    return longDateLabel(start)
  }

  return `${start.toLocaleDateString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  })} – ${last.toLocaleDateString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  })}`
}

function incrementMap(map: Map<string, FinishedReportTopItem>, label: string, iconLabel?: string) {
  const clean = String(label || '').trim()
  if (!clean) return

  const key = clean.toLowerCase()
  const current = map.get(key)

  if (current) {
    current.count += 1
    return
  }

  map.set(key, {
    label: clean,
    iconLabel,
    count: 1,
  })
}

function topItems(map: Map<string, FinishedReportTopItem>, limit = 8) {
  return Array.from(map.values())
    .sort((a, b) => b.count - a.count || a.label.localeCompare(b.label, 'de'))
    .slice(0, limit)
}

function buildReportStats(rows: RecordJob[], mode: FinishedReportMode): FinishedReportStats {
  const { start, end } = reportPeriod(mode)

  const modelCounts = new Map<string, FinishedReportTopItem>()
  const tagCounts = new Map<string, FinishedReportTopItem>()

  const dailyMap = new Map<string, FinishedReportDailyItem>()
  for (let d = new Date(start); d < end; d = addDays(d, 1)) {
    const key = dateKey(d)
    dailyMap.set(key, {
      key,
      label: shortDateLabel(d),
      count: 0,
      durationSeconds: 0,
      sizeBytes: 0,
    })
  }

  const ratingCounts: Record<1 | 2 | 3 | 4 | 5, number> = {
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 0,
  }

  let totalCount = 0
  let totalDurationSeconds = 0
  let totalSizeBytes = 0
  let knownSizeCount = 0
  let hotCount = 0
  let keepCount = 0
  let ratedCount = 0

  for (const job of rows) {
    const d = readJobDate(job)
    if (!d || d < start || d >= end) continue

    totalCount++

    const output = String((job as any)?.output ?? '')
    if (isHotOutput(output)) hotCount++
    if (isKeepOutput(output)) keepCount++

    const duration = readJobDurationSeconds(job)
    if (duration != null) {
      totalDurationSeconds += duration
    }

    const sizeBytes = readJobSizeBytes(job)
    if (sizeBytes != null) {
      totalSizeBytes += sizeBytes
      knownSizeCount++
    }

    const bucket = dailyMap.get(dateKey(d))
    if (bucket) {
      bucket.count += 1
      bucket.durationSeconds += duration ?? 0
      bucket.sizeBytes += sizeBytes ?? 0
    }

    const model = modelNameFromOutput(output)
    if (model && model !== '—') {
      incrementMap(modelCounts, model)
    }

    for (const tag of autoTagsForJob(job)) {
      incrementMap(tagCounts, tag, tag)
    }

    const stars = ratingStarsForJob(job)
    if (stars != null) {
      ratedCount++
      ratingCounts[stars as 1 | 2 | 3 | 4 | 5] += 1
    }
  }

  return {
    mode,
    start,
    end,
    totalCount,
    totalDurationSeconds,
    totalSizeBytes,
    knownSizeCount,
    hotCount,
    keepCount,
    ratedCount,
    ratingCounts,
    topModels: topItems(modelCounts, 8),
    topTags: topItems(tagCounts, 10),
    daily: Array.from(dailyMap.values()),
  }
}

function ReportMetric({
  label,
  value,
  sub,
  icon,
  tone = 'slate',
}: {
  label: string
  value: ReactNode
  sub?: ReactNode
  icon: ReactNode
  tone?: 'slate' | 'sky' | 'amber' | 'emerald' | 'rose'
}) {
  const toneCls =
    tone === 'sky'
      ? 'border-sky-200 bg-sky-50/80 text-sky-700 dark:border-sky-400/20 dark:bg-sky-400/10 dark:text-sky-200'
      : tone === 'amber'
        ? 'border-amber-200 bg-amber-50/80 text-amber-700 dark:border-amber-400/20 dark:bg-amber-400/10 dark:text-amber-200'
        : tone === 'emerald'
          ? 'border-emerald-200 bg-emerald-50/80 text-emerald-700 dark:border-emerald-400/20 dark:bg-emerald-400/10 dark:text-emerald-200'
          : tone === 'rose'
            ? 'border-rose-200 bg-rose-50/80 text-rose-700 dark:border-rose-400/20 dark:bg-rose-400/10 dark:text-rose-200'
            : 'border-gray-200 bg-gray-50/90 text-gray-600 dark:border-white/10 dark:bg-white/5 dark:text-gray-300'

  return (
    <div className={['rounded-2xl border p-3 shadow-sm', toneCls].join(' ')}>
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <div className="text-[10px] font-black uppercase tracking-wide opacity-80">
            {label}
          </div>

          <div className="mt-1 min-w-0 text-2xl font-black leading-tight text-gray-950 dark:text-white">
            {value}
          </div>

          {sub ? (
            <div className="mt-1 truncate text-[11px] font-medium text-gray-500 dark:text-gray-400">
              {sub}
            </div>
          ) : null}
        </div>

        <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-white/70 ring-1 ring-black/5 dark:bg-white/10 dark:ring-white/10">
          {icon}
        </div>
      </div>
    </div>
  )
}

function ReportBarList({
  title,
  items,
  empty,
  icons = false,
}: {
  title: string
  items: FinishedReportTopItem[]
  empty: string
  icons?: boolean
}) {
  const max = Math.max(1, items[0]?.count ?? 1)
  const total = items.reduce((sum, item) => sum + item.count, 0)

  return (
    <section className="overflow-hidden rounded-2xl border border-gray-200/70 bg-white/80 shadow-sm dark:border-white/10 dark:bg-white/[0.04]">
      <div className="flex items-center justify-between gap-3 border-b border-gray-200/70 bg-gray-50/80 px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.03]">
        <div>
          <div className="text-sm font-bold text-gray-900 dark:text-white">
            {title}
          </div>
          <div className="text-[11px] text-gray-500 dark:text-gray-400">
            {items.length > 0 ? `${fmtInt(total)} Treffer gesamt` : 'Keine Daten'}
          </div>
        </div>

        <span className="rounded-full bg-white px-2 py-0.5 text-[11px] font-bold text-gray-600 ring-1 ring-gray-200 dark:bg-white/5 dark:text-gray-300 dark:ring-white/10">
          Top {fmtInt(items.length)}
        </span>
      </div>

      <div className="p-3">
        {items.length === 0 ? (
          <div className="rounded-xl bg-gray-50 p-3 text-sm text-gray-500 ring-1 ring-gray-200 dark:bg-white/5 dark:text-gray-400 dark:ring-white/10">
            {empty}
          </div>
        ) : (
          <div className="space-y-2">
            {items.map((item, index) => {
              const width = `${Math.max(8, Math.round((item.count / max) * 100))}%`
              const share = total > 0 ? Math.round((item.count / total) * 100) : 0

              return (
                <div
                  key={item.label}
                  className="rounded-2xl bg-gray-50 p-2.5 ring-1 ring-black/5 transition hover:bg-gray-100/80 dark:bg-white/5 dark:ring-white/10 dark:hover:bg-white/10"
                >
                  <div className="flex items-center justify-between gap-3">
                    <div className="flex min-w-0 items-center gap-2.5">
                      <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-white text-[11px] font-black text-gray-500 ring-1 ring-gray-200 dark:bg-gray-950/40 dark:text-gray-400 dark:ring-white/10">
                        #{index + 1}
                      </span>

                      {icons ? (
                        <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-indigo-50 text-indigo-700 ring-1 ring-indigo-200 dark:bg-indigo-500/15 dark:text-indigo-100 dark:ring-indigo-300/30">
                          <SegmentLabelIcon
                            label={item.iconLabel ?? item.label}
                            className="h-4.5 w-4.5"
                          />
                        </span>
                      ) : null}

                      <div className="min-w-0">
                        <div className="truncate text-sm font-bold text-gray-900 dark:text-white">
                          {item.label}
                        </div>
                        <div className="text-[11px] text-gray-500 dark:text-gray-400">
                          {share}% Anteil
                        </div>
                      </div>
                    </div>

                    <span className="shrink-0 rounded-full bg-indigo-50 px-2 py-0.5 text-[11px] font-black text-indigo-700 ring-1 ring-indigo-200 dark:bg-indigo-500/15 dark:text-indigo-100 dark:ring-indigo-300/30">
                      {fmtInt(item.count)}
                    </span>
                  </div>

                  <div className="mt-2 h-2 overflow-hidden rounded-full bg-gray-200 dark:bg-white/10">
                    <div
                      className="h-full rounded-full bg-indigo-500 dark:bg-indigo-400"
                      style={{ width }}
                    />
                  </div>
                </div>
              )
            })}
          </div>
        )}
      </div>
    </section>
  )
}

function DailyBars({ items }: { items: FinishedReportDailyItem[] }) {
  const max = Math.max(1, ...items.map((item) => item.count))
  const total = items.reduce((sum, item) => sum + item.count, 0)

  return (
    <section className="overflow-hidden rounded-2xl border border-gray-200/70 bg-white/80 shadow-sm dark:border-white/10 dark:bg-white/[0.04]">
      <div className="flex items-center justify-between gap-3 border-b border-gray-200/70 bg-gray-50/80 px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.03]">
        <div>
          <div className="text-sm font-bold text-gray-900 dark:text-white">
            Verlauf
          </div>
          <div className="text-[11px] text-gray-500 dark:text-gray-400">
            Downloads pro Tag
          </div>
        </div>

        <ChartBarIcon className="h-5 w-5 text-sky-500 dark:text-sky-300" />
      </div>

      <div className="p-3">
        <div className="space-y-2.5">
          {items.map((item) => {
            const width = `${Math.max(item.count > 0 ? 8 : 0, Math.round((item.count / max) * 100))}%`
            const share = total > 0 ? Math.round((item.count / total) * 100) : 0

            return (
              <div key={item.key}>
                <div className="mb-1 flex items-center justify-between gap-3 text-xs">
                  <span className="font-semibold text-gray-700 dark:text-gray-200">
                    {item.label}
                  </span>
                  <span className="text-gray-500 dark:text-gray-400">
                    {fmtInt(item.count)} · {fmtDuration(item.durationSeconds)} · {share}%
                  </span>
                </div>

                <div className="h-2.5 overflow-hidden rounded-full bg-gray-200 dark:bg-white/10">
                  <div
                    className="h-full rounded-full bg-sky-500 dark:bg-sky-400"
                    style={{ width }}
                  />
                </div>
              </div>
            )
          })}
        </div>
      </div>
    </section>
  )
}

function RatingDistribution({ stats }: { stats: FinishedReportStats }) {
  const max = Math.max(1, ...([1, 2, 3, 4, 5] as const).map((n) => stats.ratingCounts[n]))

  return (
    <section className="overflow-hidden rounded-2xl border border-gray-200/70 bg-white/80 shadow-sm dark:border-white/10 dark:bg-white/[0.04]">
      <div className="flex items-center justify-between gap-3 border-b border-gray-200/70 bg-gray-50/80 px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.03]">
        <div>
          <div className="text-sm font-bold text-gray-900 dark:text-white">
            Bewertung
          </div>
          <div className="text-[11px] text-gray-500 dark:text-gray-400">
            {fmtInt(stats.ratedCount)} bewertete Downloads
          </div>
        </div>

        <StarIcon className="h-5 w-5 text-amber-500 dark:text-amber-300" />
      </div>

      <div className="p-3">
        <div className="space-y-2.5">
          {([5, 4, 3, 2, 1] as const).map((stars) => {
            const count = stats.ratingCounts[stars]
            const width = `${Math.max(count > 0 ? 8 : 0, Math.round((count / max) * 100))}%`

            return (
              <div key={stars}>
                <div className="mb-1 flex items-center justify-between gap-3 text-xs">
                  <span className="font-semibold text-gray-700 dark:text-gray-200">
                    {'★'.repeat(stars)}
                    <span className="ml-1 text-gray-400">
                      {'★'.repeat(5 - stars)}
                    </span>
                  </span>
                  <span className="text-gray-500 dark:text-gray-400">
                    {fmtInt(count)}
                  </span>
                </div>

                <div className="h-2.5 overflow-hidden rounded-full bg-gray-200 dark:bg-white/10">
                  <div
                    className="h-full rounded-full bg-amber-400 dark:bg-amber-300"
                    style={{ width }}
                  />
                </div>
              </div>
            )
          })}
        </div>
      </div>
    </section>
  )
}

export default function FinishedReportModal({
  open,
  onClose,
}: {
  open: boolean
  onClose: () => void
}) {
  const [mode, setMode] = useState<FinishedReportMode>('day')
  const [rows, setRows] = useState<RecordJob[]>([])
  const [availableCount, setAvailableCount] = useState(0)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')

  const loadReportRows = useCallback(async () => {
    setLoading(true)
    setError('')

    try {
      const url =
        `/api/record/done?page=1&pageSize=${REPORT_PAGE_SIZE}` +
        `&sort=completed_desc&includeKeep=1&withCount=1`

      const r = await fetch(url, { cache: 'no-store' })
      const data = await r.json().catch(() => null)

      if (!r.ok) {
        throw new Error(String(data?.error || data?.message || `HTTP ${r.status}`))
      }

      const items = Array.isArray(data?.items) ? data.items as RecordJob[] : []
      const count = Number(data?.count ?? items.length)

      setRows(items)
      setAvailableCount(Number.isFinite(count) ? count : items.length)
    } catch (err: any) {
      setError(err?.message || 'Report konnte nicht geladen werden.')
      setRows([])
      setAvailableCount(0)
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    if (!open) return
    void loadReportRows()
  }, [open, loadReportRows])

  const stats = useMemo(() => {
    return buildReportStats(rows, mode)
  }, [rows, mode])

  const partialHint =
    availableCount > rows.length
      ? `Es werden die neuesten ${fmtInt(rows.length)} von ${fmtInt(availableCount)} Downloads berücksichtigt.`
      : `${fmtInt(rows.length)} Downloads geladen.`

  const avgDuration =
    stats.totalCount > 0 ? stats.totalDurationSeconds / stats.totalCount : 0

  const avgSize =
    stats.knownSizeCount > 0 ? stats.totalSizeBytes / stats.knownSizeCount : 0

  const reportModeSwitch = (
    <ButtonGroup
      value={mode}
      onChange={(id) => setMode(id as FinishedReportMode)}
      size="md"
      ariaLabel="Report-Zeitraum"
      items={[
        {
          id: 'day',
          label: 'Heute',
          icon: <CalendarDaysIcon className="size-4" />,
        },
        {
          id: 'week',
          label: 'Diese Woche',
          icon: <ChartBarIcon className="size-4" />,
        },
      ]}
    />
  )

  const refreshButton = (
    <Button
      type="button"
      size="sm"
      rounded="md"
      variant="secondary"
      color="indigo"
      onClick={() => void loadReportRows()}
      isLoading={loading}
      leadingIcon={<ArrowPathIcon className="h-4 w-4" />}
    >
      Aktualisieren
    </Button>
  )

  return (
    <Modal
      open={open}
      onClose={onClose}
      title="Tages-/Wochenreport"
      width="max-w-6xl"
      scroll="body"
      rightClassName="bg-gray-50/60 dark:bg-gray-950/20"
      titleRight={
        <div className="flex items-center gap-2">
          {reportModeSwitch}
          {refreshButton}
        </div>
      }
    >
      <div className="space-y-4 p-4 sm:p-5">
        <div className="flex flex-wrap items-center justify-between gap-2 sm:hidden">
          {reportModeSwitch}
          {refreshButton}
        </div>
        <section className="overflow-hidden rounded-3xl border border-gray-200/70 bg-gradient-to-br from-white via-sky-50/70 to-indigo-50/70 shadow-sm dark:border-white/10 dark:from-white/[0.06] dark:via-sky-400/10 dark:to-indigo-400/10">
          <div className="p-4">
            <div className="flex flex-wrap items-start justify-between gap-3">
              <div className="min-w-0">
                <div className="inline-flex items-center gap-2 rounded-full bg-white/80 px-2.5 py-1 text-[11px] font-bold text-indigo-700 ring-1 ring-indigo-200 dark:bg-white/10 dark:text-indigo-100 dark:ring-indigo-300/30">
                  <CalendarDaysIcon className="h-4 w-4" />
                  {mode === 'day' ? 'Tagesreport' : 'Wochenreport'}
                </div>

                <h2 className="mt-3 text-2xl font-black tracking-tight text-gray-950 dark:text-white">
                  {mode === 'day' ? 'Heute' : 'Diese Woche'}
                </h2>

                <div className="mt-1 text-sm text-gray-600 dark:text-gray-300">
                  {rangeLabel(stats.start, stats.end)}
                </div>
              </div>
            </div>

            <div className="mt-4 flex flex-wrap items-center gap-2">
              {loading ? (
                <span className="inline-flex items-center gap-1.5 rounded-full bg-white/80 px-2.5 py-1 text-[11px] font-medium text-gray-500 ring-1 ring-gray-200 dark:bg-white/10 dark:text-gray-300 dark:ring-white/10">
                  <LoadingSpinner size="sm" />
                  Lädt…
                </span>
              ) : (
                <span className="rounded-full bg-white/80 px-2.5 py-1 text-[11px] font-medium text-gray-600 ring-1 ring-gray-200 dark:bg-white/10 dark:text-gray-300 dark:ring-white/10">
                  {partialHint}
                </span>
              )}

              <span className="rounded-full bg-white/80 px-2.5 py-1 text-[11px] font-medium text-gray-600 ring-1 ring-gray-200 dark:bg-white/10 dark:text-gray-300 dark:ring-white/10">
                Ø Dauer: {fmtDuration(avgDuration)}
              </span>

              <span className="rounded-full bg-white/80 px-2.5 py-1 text-[11px] font-medium text-gray-600 ring-1 ring-gray-200 dark:bg-white/10 dark:text-gray-300 dark:ring-white/10">
                Ø Größe: {avgSize > 0 ? fmtBytes(avgSize) : '—'}
              </span>
            </div>

            {error ? (
              <div className="mt-4 rounded-xl bg-red-50 p-3 text-sm text-red-700 ring-1 ring-red-200 dark:bg-red-500/10 dark:text-red-200 dark:ring-red-400/25">
                {error}
              </div>
            ) : null}

            <div className="mt-4 grid grid-cols-2 gap-3 xl:grid-cols-4">
              <ReportMetric
                label="Downloads"
                value={fmtInt(stats.totalCount)}
                sub="fertiggestellt"
                icon={<CalendarDaysIcon className="h-5 w-5" />}
                tone="sky"
              />

              <ReportMetric
                label="Laufzeit"
                value={fmtDuration(stats.totalDurationSeconds)}
                sub="Videodauer"
                icon={<ClockIcon className="h-5 w-5" />}
              />

              <ReportMetric
                label="Speicher"
                value={stats.knownSizeCount > 0 ? fmtBytes(stats.totalSizeBytes) : '—'}
                sub={stats.knownSizeCount > 0 ? `${fmtInt(stats.knownSizeCount)} Dateien` : 'keine Größen'}
                icon={<ArchiveBoxIcon className="h-5 w-5" />}
                tone="emerald"
              />

              <ReportMetric
                label="Markiert"
                value={`${fmtInt(stats.hotCount)} / ${fmtInt(stats.keepCount)}`}
                sub="HOT / Keep"
                icon={<FireIcon className="h-5 w-5" />}
                tone="amber"
              />
            </div>
          </div>
        </section>

        <div className="grid gap-4 xl:grid-cols-[0.9fr_1.1fr]">
          <DailyBars items={stats.daily} />
          <RatingDistribution stats={stats} />
        </div>

        <div className="grid gap-4 xl:grid-cols-2">
          <ReportBarList
            title="Top Models"
            items={stats.topModels}
            empty="In diesem Zeitraum wurden keine Models gefunden."
          />

          <ReportBarList
            title="Top Inhalte"
            items={stats.topTags}
            empty="In diesem Zeitraum wurden keine Auto-Tags gefunden."
            icons
          />
        </div>
      </div>
    </Modal>
  )
}