import { useState, useEffect, useMemo } from 'react'
import { Link } from 'react-router-dom'
import dayjs from 'dayjs'
import { api } from '../../utils/api'
import { getBfCategory } from '../../utils/calc'
import { useProfile } from '../../context/ProfileContext'
import { KPI_KCAL_WINDOW_DEFAULT } from '../../widgetSystem/bodyChartDays'
import { kpiTileOrderFromConfig } from '../../widgetSystem/kpiBoardTiles'
import KpiTilesOverview from '../KpiTilesOverview'

const MAX_KPI = 9

function formatRefVal(row) {
  if (row.value_numeric != null && row.value_numeric !== '') {
    const n = Number(row.value_numeric)
    return Number.isFinite(n) ? String(n) : String(row.value_numeric)
  }
  return row.value_text != null ? String(row.value_text) : '–'
}

function parseRefTypeKey(tileId) {
  if (!tileId.startsWith('ref:')) return null
  return tileId.slice(4) || null
}

function buildAutoTileIds(refTiles, hasBf, hasKcal) {
  const ids = []
  for (const t of refTiles) {
    if (t?.type_key) ids.push(`ref:${t.type_key}`)
  }
  if (hasBf) ids.push('body_fat')
  if (hasKcal) ids.push('avg_kcal')
  return ids.slice(0, MAX_KPI)
}

/**
 * KPIs: Referenzwerte, Körperfett, Ø Kalorien — max. 9 Kacheln.
 * @param {{ refreshTick?: number, kpiConfig?: Record<string, unknown> }} props
 * kpiConfig.tiles: geordnete Kachel-ids; fehlend = automatische Belegung (wie bisher).
 */
export default function KpiBoardWidget({ refreshTick = 0, kpiConfig }) {
  const manualOrder = useMemo(() => kpiTileOrderFromConfig(kpiConfig), [kpiConfig])

  const { activeProfile } = useProfile()
  const sex = activeProfile?.sex || 'm'
  const [refTiles, setRefTiles] = useState([])
  const [refByKey, setRefByKey] = useState(() => new Map())
  const [bf, setBf] = useState(null)
  const [avgKcal, setAvgKcal] = useState(null)
  const [loading, setLoading] = useState(true)
  const [err, setErr] = useState(null)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      try {
        setLoading(true)
        const kcalDays = KPI_KCAL_WINDOW_DEFAULT
        const nutrLimit = Math.min(2000, Math.max(60, kcalDays * 5))
        const [summary, calipers, nutrition] = await Promise.all([
          api.listProfileReferenceValuesSummary().catch(() => ({ tiles: [] })),
          api.listCaliper(3).catch(() => []),
          api.listNutrition(nutrLimit).catch(() => []),
        ])
        if (cancelled) return
        const tiles = Array.isArray(summary?.tiles) ? summary.tiles.filter((t) => t?.latest) : []
        const map = new Map(tiles.map((t) => [t.type_key, t]))
        const latestCal = Array.isArray(calipers) && calipers[0]?.body_fat_pct != null ? calipers[0] : null
        const recentNutr = (nutrition || []).filter(
          (n) => n.date >= dayjs().subtract(kcalDays, 'day').format('YYYY-MM-DD'),
        )
        const kcal =
          recentNutr.length > 0
            ? Math.round(recentNutr.reduce((s, n) => s + (n.kcal || 0), 0) / recentNutr.length)
            : null

        const wantBf = !!latestCal?.body_fat_pct
        const wantKcal = kcal != null && kcal > 0

        setRefTiles(tiles)
        setRefByKey(map)
        setBf(
          wantBf
            ? {
                pct: latestCal.body_fat_pct,
                cat: getBfCategory(latestCal.body_fat_pct, sex),
                date: latestCal.date,
              }
            : null,
        )
        setAvgKcal(wantKcal ? kcal : null)
        setErr(null)
      } catch (e) {
        if (!cancelled) {
          setErr(e.message || 'KPIs konnten nicht geladen werden')
          setRefTiles([])
          setRefByKey(new Map())
        }
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [refreshTick, sex])

  const orderIds = useMemo(() => {
    if (manualOrder !== undefined) {
      return manualOrder
    }
    const hasBf = !!bf
    const hasKcal = avgKcal != null && avgKcal > 0
    return buildAutoTileIds(refTiles, hasBf, hasKcal)
  }, [manualOrder, refTiles, bf, avgKcal])

  const kpiTiles = useMemo(() => {
    const out = []
    for (const id of orderIds) {
      if (id === 'body_fat') {
        if (!bf) continue
        out.push({
          key: 'kpi-bf',
          status: 'good',
          category: 'Körperfett',
          icon: '🫧',
          value: `${bf.pct}%`,
          sublabel: bf.cat?.label || 'Caliper',
          valueColor: bf.cat?.color,
          hoverTop: 'Körperfett (Caliper)',
          hoverBody:
            `Letzte Messung: ${bf.date ? dayjs(bf.date).format('DD.MM.YYYY') : '—'}.\n` +
            'Wert aus dem Caliper-Log; die Farbe/Kategorie richtet sich nach Geschlecht und üblicher Spanne.',
        })
        continue
      }
      if (id === 'avg_kcal') {
        if (avgKcal == null) continue
        out.push({
          key: 'kpi-kcal',
          status: 'good',
          category: `Ø Kalorien (${KPI_KCAL_WINDOW_DEFAULT}T)`,
          icon: '🍽️',
          value: `${avgKcal} kcal`,
          sublabel: 'Ernährung',
          valueColor: '#EF9F27',
          hoverTop: `Ø Kalorien (${KPI_KCAL_WINDOW_DEFAULT} Tage)`,
          hoverBody:
            `Durchschnitt der täglichen Kalorien aus dem Ernährungs-Log über die letzten ${KPI_KCAL_WINDOW_DEFAULT} Tage (Mittel über alle geladenen Tageseinträge im Fenster).`,
        })
        continue
      }
      const tk = parseRefTypeKey(id)
      if (!tk) continue
      const tile = refByKey.get(tk)
      if (!tile?.latest) continue
      const l = tile.latest
      const valStr = formatRefVal(l)
      const withUnit = l.unit ? `${valStr} ${l.unit}`.trim() : valStr
      out.push({
        key: `ref-${tk}`,
        status: 'good',
        category: tile.type_label,
        icon: '📌',
        value: withUnit,
        sublabel: 'Ref.wert',
        hoverTop: tile.type_label,
        hoverBody:
          'Persönlicher Referenzwert aus dem Profil. Verwaltung unter Einstellungen → Referenzwerte.',
      })
    }
    return out
  }, [orderIds, bf, avgKcal, refByKey])

  if (loading) {
    return (
      <div className="card section-gap" style={{ textAlign: 'center', padding: 24 }}>
        <div className="spinner" />
      </div>
    )
  }
  if (err) {
    return (
      <div className="card section-gap" style={{ color: 'var(--danger)', fontSize: 13 }}>
        {err}
      </div>
    )
  }

  if (kpiTiles.length === 0) {
    return (
      <div className="card section-gap">
        <div className="card-title">Kennzahlen</div>
        <p style={{ fontSize: 13, color: 'var(--text2)', margin: 0 }}>
          Noch keine Daten oder keine passenden Kacheln.{' '}
          <Link to="/settings/reference-values" style={{ color: 'var(--accent)' }}>
            Referenzwerte
          </Link>
          ,{' '}
          <Link to="/caliper" style={{ color: 'var(--accent)' }}>
            Caliper
          </Link>
          ,{' '}
          <Link to="/nutrition" style={{ color: 'var(--accent)' }}>
            Ernährung
          </Link>
          .
        </p>
      </div>
    )
  }

  return (
    <div className="card section-gap">
      <div className="card-title">Kennzahlen</div>
      <p style={{ fontSize: 12, color: 'var(--text2)', marginBottom: 12, lineHeight: 1.5 }}>
        {manualOrder !== undefined
          ? 'Ausgewählte Kacheln in festgelegter Reihenfolge (ohne Daten werden Kacheln ausgelassen).'
          : `Bis ${MAX_KPI} Kacheln: Referenzwerte, Körperfett, Ø Kalorien (${KPI_KCAL_WINDOW_DEFAULT}T).`}
      </p>
      <KpiTilesOverview
        tiles={kpiTiles}
        heading={null}
        showTouchHint
        gridClassName="ref-value-tiles-grid"
        marginBottom={0}
      />
    </div>
  )
}
