import { useState, useEffect, useRef, useCallback, startTransition } from 'react'
import { Upload, Pencil, Trash2, Check, X, CheckCircle } from 'lucide-react'
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid } from 'recharts'
import { api } from '../utils/api'
import UsageBadge from '../components/UsageBadge'
import TrainingTypeSelect from '../components/TrainingTypeSelect'
import BulkCategorize from '../components/BulkCategorize'
import dayjs from 'dayjs'
import 'dayjs/locale/de'
dayjs.locale('de')

/** Erfassungsseite /activity: pro Kalendermonat laden (ohne Qualitätsfilter, siehe Backend). */
const ACTIVITY_MONTH_FETCH_LIMIT = 25_000

function ymdMonth(d = dayjs()) {
  return d.format('YYYY-MM')
}

function prevMonthYm(ym) {
  return dayjs(`${ym}-01`).subtract(1, 'month').format('YYYY-MM')
}

function compareActivities(a, b) {
  const da = a.date || ''
  const db = b.date || ''
  if (da !== db) return db.localeCompare(da)
  const sa = String(a.start_time || '')
  const sb = String(b.start_time || '')
  if (sa !== sb) return sb.localeCompare(sa)
  return String(b.id || '').localeCompare(String(a.id || ''))
}

function dedupeActivitiesById(rows) {
  const m = new Map()
  for (const r of rows) {
    if (r?.id) m.set(r.id, r)
  }
  return [...m.values()].sort(compareActivities)
}

/** activity_log: Spalten start_time / end_time sind TIME (Uhrzeit zum Kalendertag date), nicht volles Timestamp. */
function timeInputValueFromApi(t) {
  if (t == null || t === '') return ''
  const s = String(t)
  if (s.includes('T') && s.length >= 16) return s.slice(11, 16)
  const m = s.match(/^(\d{1,2}):(\d{2})/)
  if (!m) return ''
  return `${m[1].padStart(2, '0')}:${m[2]}`
}

function timePayloadFromInput(v) {
  const s = v == null ? '' : String(v).trim()
  if (!s) return null
  if (/^\d{2}:\d{2}$/.test(s)) return `${s}:00`
  if (/^\d{2}:\d{2}:\d{2}$/.test(s)) return s
  return s
}

function formatTimeForList(t) {
  const v = timeInputValueFromApi(t)
  return v || ''
}

const ACTIVITY_TYPES = [
  'Traditionelles Krafttraining','Matrial Arts','Outdoor Spaziergang',
  'Innenräume Spaziergang','Laufen','Radfahren','Schwimmen',
  'Cardio Dance','Geist & Körper','Sonstiges'
]

/** Spalten, die mit ActivityEntry / UPDATE activity_log geschrieben werden dürfen (Übergang: Profilfelder → Kopfzeile). */
const ACTIVITY_LOG_PAYLOAD_KEYS = new Set([
  'date',
  'start_time',
  'end_time',
  'activity_type',
  'duration_min',
  'kcal_active',
  'kcal_resting',
  'hr_avg',
  'hr_max',
  'hr_min',
  'distance_km',
  'pace_min_per_km',
  'cadence',
  'avg_power',
  'elevation_gain',
  'temperature_celsius',
  'humidity_percent',
  'avg_hr_percent',
  'kcal_per_km',
  'rpe',
  'source',
  'notes',
  'training_type_id',
  'training_category',
  'training_subcategory',
])

/** activity_log-Spalten, die bereits in EntryForm (Kopfzeile) bearbeitet werden — Profilfeld mit gleichem source_field nicht doppelt anzeigen. */
const ENTRY_FORM_ACTIVITY_LOG_COLUMNS = new Set([
  'duration_min',
  'kcal_active',
  'hr_avg',
  'hr_max',
  'rpe',
  'notes',
])

/**
 * Bindung Profilparameter ↔ Kopfzeile: Entweder source_field zeigt auf eine Kopfspalte,
 * oder der Parameter-key ist selbst eine Kopfspalte (häufig nach Migration / ohne source_field).
 * @returns {{ headlineCol: string, parameterKey: string } | null}
 */
function activitySchemaHeadlineBinding(s) {
  if (!s || !s.key) return null
  const sf = s.source_field != null ? String(s.source_field).trim() : ''
  if (sf && ENTRY_FORM_ACTIVITY_LOG_COLUMNS.has(sf)) {
    return { headlineCol: sf, parameterKey: s.key }
  }
  if (ENTRY_FORM_ACTIVITY_LOG_COLUMNS.has(s.key)) {
    return { headlineCol: s.key, parameterKey: s.key }
  }
  return null
}

/** training_parameters.category (siehe Migration 013); feste Reihenfolge der Wertegruppen */
const TRAINING_PARAM_CATEGORY_ORDER = [
  'physical',
  'physiological',
  'performance',
  'subjective',
  'environmental',
]

const TRAINING_PARAM_CATEGORY_LABEL_DE = {
  physical: 'Physisch / Bewegung',
  physiological: 'Physiologie',
  performance: 'Leistung',
  subjective: 'Subjektiv und Wahrnehmung',
  environmental: 'Umwelt',
}

function compareActivityProfileSchemaRows(a, b) {
  const ca = (a.param_category && String(a.param_category).trim().toLowerCase()) || ''
  const cb = (b.param_category && String(b.param_category).trim().toLowerCase()) || ''
  const ia = TRAINING_PARAM_CATEGORY_ORDER.indexOf(ca)
  const ib = TRAINING_PARAM_CATEGORY_ORDER.indexOf(cb)
  const ra = ia === -1 ? 1000 : ia
  const rb = ib === -1 ? 1000 : ib
  if (ra !== rb) return ra - rb
  if (ca !== cb) return ca.localeCompare(cb, 'de')

  const ga = (a.ui_group && String(a.ui_group).trim()) || ''
  const gb = (b.ui_group && String(b.ui_group).trim()) || ''
  if (ga !== gb) {
    if (!ga) return -1
    if (!gb) return 1
    return ga.localeCompare(gb, 'de')
  }
  const sa = Number(a.sort_order) || 0
  const sb = Number(b.sort_order) || 0
  if (sa !== sb) return sa - sb
  return String(a.key).localeCompare(String(b.key), 'de')
}

function sortActivityProfileSchemaRows(rows) {
  return [...rows].sort(compareActivityProfileSchemaRows)
}

function empty() {
  return {
    date: dayjs().format('YYYY-MM-DD'),
    start_time: '',
    end_time: '',
    activity_type: 'Traditionelles Krafttraining',
    duration_min: '', kcal_active: '',
    hr_avg: '', hr_max: '', rpe: '', notes: '',
    training_type_id: null,
    training_category: null,
    training_subcategory: null
  }
}

function buildMetricsPayload(schema, draft) {
  const out = []
  for (const s of schema) {
    const raw = draft[s.key]
    if (s.data_type === 'boolean') {
      if (raw === '' || raw === null || raw === undefined) {
        if (s.required) throw new Error(`Pflichtfeld: ${s.name_de}`)
        out.push({ parameter_key: s.key, value: null })
        continue
      }
      out.push({ parameter_key: s.key, value: !!raw })
      continue
    }
    const rawStr = raw === null || raw === undefined ? '' : String(raw).trim()
    if (rawStr === '') {
      if (s.required) throw new Error(`Pflichtfeld: ${s.name_de}`)
      out.push({ parameter_key: s.key, value: null })
      continue
    }
    let v
    if (s.data_type === 'integer') {
      v = parseInt(rawStr, 10)
      if (Number.isNaN(v)) throw new Error(`Ungültige Zahl: ${s.name_de}`)
    } else if (s.data_type === 'float') {
      v = parseFloat(rawStr)
      if (Number.isNaN(v)) throw new Error(`Ungültige Zahl: ${s.name_de}`)
    } else {
      v = rawStr
    }
    out.push({ parameter_key: s.key, value: v })
  }
  return out
}

function SessionMetricsFields({ schema, values, setValues, metrics }) {
  const schemaList = Array.isArray(schema) ? schema : []
  const headlineDuplicateKeys = new Set(
    schemaList.filter((s) => activitySchemaHeadlineBinding(s) != null).map((s) => s.key),
  )
  const schemaForDisplay = schemaList.filter((s) => activitySchemaHeadlineBinding(s) == null)
  const metricRows = Array.isArray(metrics) ? metrics : []
  const schemaKeys = new Set(schemaForDisplay.map((s) => s.key))
  const orphanMetrics = metricRows.filter(
    (row) =>
      row &&
      row.key &&
      !schemaKeys.has(row.key) &&
      !headlineDuplicateKeys.has(row.key),
  )

  if (schemaForDisplay.length === 0 && orphanMetrics.length === 0) return null
  const set = (k, v) => setValues((prev) => ({ ...prev, [k]: v }))

  const sortedForDisplay = sortActivityProfileSchemaRows(schemaForDisplay)
  const profileFieldNodes = []
  let lastCategoryKey = null
  let lastUiGroup = null
  for (const s of sortedForDisplay) {
    const catRaw = (s.param_category && String(s.param_category).trim().toLowerCase()) || ''
    const catKey = catRaw || '_other'
    if (catKey !== lastCategoryKey) {
      lastCategoryKey = catKey
      lastUiGroup = null
      const catTitle =
        (catRaw && TRAINING_PARAM_CATEGORY_LABEL_DE[catRaw]) || s.param_category || 'Sonstige'
      profileFieldNodes.push(
        <div
          key={`prof-cat-${catKey}-${profileFieldNodes.length}`}
          style={{
            fontSize: 12,
            fontWeight: 700,
            color: 'var(--text2)',
            marginTop: profileFieldNodes.length ? 14 : 6,
            marginBottom: 6,
            letterSpacing: '0.02em',
          }}
        >
          {catTitle}
        </div>,
      )
    }
    const ug = (s.ui_group && String(s.ui_group).trim()) || ''
    if (ug) {
      if (ug !== lastUiGroup) {
        lastUiGroup = ug
        profileFieldNodes.push(
          <div
            key={`prof-ug-${catKey}-${ug}-${profileFieldNodes.length}`}
            style={{ fontSize: 12, color: 'var(--text3)', marginTop: 8, marginBottom: 4 }}
          >
            {ug}
          </div>,
        )
      }
    } else {
      lastUiGroup = null
    }
    profileFieldNodes.push(
      <div key={s.key} className="form-row">
        <label className="form-label">
          {s.name_de}
          {s.required ? ' *' : ''}
          {s.unit ? ` (${s.unit})` : ''}
        </label>
        {s.data_type === 'boolean' ? (
          <input
            type="checkbox"
            style={{ width: 'auto', marginRight: 'auto' }}
            checked={!!values[s.key]}
            onChange={(e) => set(s.key, e.target.checked)}
          />
        ) : s.data_type === 'integer' || s.data_type === 'float' ? (
          <input
            type="number"
            className="form-input"
            step={s.data_type === 'integer' ? 1 : 'any'}
            value={values[s.key] ?? ''}
            onChange={(e) => set(s.key, e.target.value)}
          />
        ) : (
          <input
            type="text"
            className="form-input"
            value={values[s.key] ?? ''}
            onChange={(e) => set(s.key, e.target.value)}
          />
        )}
        <span className="form-unit" />
      </div>,
    )
  }

  const orphansSorted = [...orphanMetrics].sort((a, b) =>
    String(a.key).localeCompare(String(b.key), 'de'),
  )

  return (
    <div style={{ marginTop: 12, paddingTop: 12, borderTop: '1px solid var(--border)' }}>
      <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 8 }}>Weitere Kennwerte (Profil)</div>
      {profileFieldNodes}
      {orphanMetrics.length > 0 && (
        <div style={{ marginTop: 14 }}>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 8, lineHeight: 1.45 }}>
            Werte aus Import/älteren Daten, die zum <strong>aktuellen</strong> Trainingsprofil dieser Session (Kategorie/Typ
            in activity_log) nicht ins Schema passen — nur Anzeige. Sichtbar nach erneutem Laden, wenn die Daten in der
            Datenbank stehen.
          </div>
          {orphansSorted.map((row) => {
            const disp =
              values[row.key] === null || values[row.key] === undefined || values[row.key] === ''
                ? '—'
                : String(values[row.key])
            return (
              <div key={row.key} className="form-row">
                <label className="form-label">
                  {row.key}
                  {row.unit ? ` (${row.unit})` : ''}
                </label>
                {row.data_type === 'boolean' ? (
                  <input type="checkbox" style={{ width: 'auto', marginRight: 'auto' }} checked={!!values[row.key]} readOnly disabled />
                ) : (
                  <div
                    className="form-input"
                    style={{
                      background: 'var(--surface2)',
                      cursor: 'default',
                      color: 'var(--text1)',
                    }}
                  >
                    {disp}
                  </div>
                )}
                <span className="form-unit" />
              </div>
            )
          })}
        </div>
      )}
    </div>
  )
}

// ── Import Panel ──────────────────────────────────────────────────────────────
function ImportPanel({ onImported }) {
  const fileRef = useRef()
  const [status,   setStatus]   = useState(null)
  const [error,    setError]    = useState(null)
  const [dragging, setDragging] = useState(false)

  const runImport = async (file) => {
    setStatus('loading'); setError(null)
    try {
      const result = await api.importActivityCsv(file)
      setStatus(result); onImported()
    } catch(err) {
      setError('Import fehlgeschlagen: ' + err.message); setStatus(null)
    }
  }

  return (
    <div className="card section-gap">
      <div className="card-title">📥 Apple Health Import</div>
      <p style={{fontSize:13,color:'var(--text2)',marginBottom:10,lineHeight:1.6}}>
        <strong>Health Auto Export App</strong> → Workouts exportieren → CSV → hier hochladen.<br/>
        Nur die <em>Workouts-…csv</em> Datei wird benötigt (nicht die Detaildateien).
      </p>
      <input ref={fileRef} type="file" accept=".csv" style={{display:'none'}}
        onChange={e=>{ const f=e.target.files[0]; if(f) runImport(f); e.target.value='' }}/>
      <div
        onDragOver={e=>{e.preventDefault();setDragging(true)}}
        onDragLeave={()=>setDragging(false)}
        onDrop={e=>{e.preventDefault();setDragging(false);const f=e.dataTransfer.files[0];if(f)runImport(f)}}
        onClick={()=>fileRef.current.click()}
        style={{border:`2px dashed ${dragging?'var(--accent)':'var(--border2)'}`,borderRadius:10,
          padding:'20px 16px',textAlign:'center',background:dragging?'var(--accent-light)':'var(--surface2)',
          cursor:'pointer',transition:'all 0.15s'}}>
        <Upload size={24} style={{color:dragging?'var(--accent)':'var(--text3)',marginBottom:6}}/>
        <div style={{fontSize:13,color:dragging?'var(--accent-dark)':'var(--text2)'}}>
          {dragging?'Datei loslassen…':'CSV hierher ziehen oder tippen'}
        </div>
      </div>
      {status==='loading' && (
        <div style={{marginTop:8,display:'flex',gap:8,fontSize:13,color:'var(--text2)'}}>
          <div className="spinner" style={{width:14,height:14}}/> Importiere…
        </div>
      )}
      {error && <div style={{marginTop:8,padding:'8px 12px',background:'#FCEBEB',borderRadius:8,fontSize:13,color:'#D85A30'}}>{error}</div>}
      {status && status!=='loading' && (
        <div style={{marginTop:8,padding:'10px 12px',background:'var(--accent-light)',borderRadius:8,fontSize:13,color:'var(--accent-dark)'}}>
          <div style={{display:'flex',alignItems:'center',gap:6,marginBottom:2}}>
            <CheckCircle size={14}/><strong>Import erfolgreich</strong>
          </div>
          <div>{status.inserted} Trainings importiert · {status.skipped} übersprungen</div>
        </div>
      )}
    </div>
  )
}

// ── Manual Entry ──────────────────────────────────────────────────────────────
function EntryForm({
  form,
  setForm,
  onSave,
  onCancel,
  saveLabel = 'Speichern',
  saving = false,
  error = null,
  usage = null,
  formExtras = null,
}) {
  const set = (k,v) => setForm(f=>({...f,[k]:v}))
  return (
    <div>
      <div className="form-row">
        <label className="form-label">Datum</label>
        <input type="date" className="form-input" style={{width:140}} value={form.date} onChange={e=>set('date',e.target.value)}/>
        <span className="form-unit"/>
      </div>
      <div className="form-row">
        <label className="form-label">Start (Uhrzeit)</label>
        <input
          type="time"
          step={1}
          className="form-input"
          style={{ width: 'auto', minWidth: 140 }}
          value={timeInputValueFromApi(form.start_time)}
          onChange={(e) => set('start_time', e.target.value ? timePayloadFromInput(e.target.value) || '' : '')}
        />
        <span className="form-unit">zum Datum oben</span>
      </div>
      <div className="form-row">
        <label className="form-label">Ende (Uhrzeit)</label>
        <input
          type="time"
          step={1}
          className="form-input"
          style={{ width: 'auto', minWidth: 140 }}
          value={timeInputValueFromApi(form.end_time)}
          onChange={(e) => set('end_time', e.target.value ? timePayloadFromInput(e.target.value) || '' : '')}
        />
        <span className="form-unit">optional</span>
      </div>
      <div style={{marginBottom:12}}>
        <TrainingTypeSelect
          value={form.training_type_id}
          onChange={(typeId, category, subcategory) => {
            setForm(f => ({
              ...f,
              training_type_id: typeId,
              training_category: category,
              training_subcategory: subcategory
            }))
          }}
          required={false}
        />
      </div>
      <div className="form-row">
        <label className="form-label">Dauer</label>
        <input type="number" className="form-input" min={1} max={600} step={1}
          placeholder="–" value={form.duration_min||''} onChange={e=>set('duration_min',e.target.value)}/>
        <span className="form-unit">Min</span>
      </div>
      <div className="form-row">
        <label className="form-label">Kcal (aktiv)</label>
        <input type="number" className="form-input" min={0} max={5000} step={1}
          placeholder="–" value={form.kcal_active||''} onChange={e=>set('kcal_active',e.target.value)}/>
        <span className="form-unit">kcal</span>
      </div>
      <div className="form-row">
        <label className="form-label">HF Ø</label>
        <input type="number" className="form-input" min={40} max={220} step={1}
          placeholder="–" value={form.hr_avg||''} onChange={e=>set('hr_avg',e.target.value)}/>
        <span className="form-unit">bpm</span>
      </div>
      <div className="form-row">
        <label className="form-label">HF Max</label>
        <input type="number" className="form-input" min={40} max={220} step={1}
          placeholder="–" value={form.hr_max||''} onChange={e=>set('hr_max',e.target.value)}/>
        <span className="form-unit">bpm</span>
      </div>
      <div className="form-row">
        <label className="form-label">Intensität</label>
        <input type="number" className="form-input" min={1} max={10} step={1}
          placeholder="1–10" value={form.rpe||''} onChange={e=>set('rpe',e.target.value)}/>
        <span className="form-unit">RPE</span>
      </div>
      <div className="form-row">
        <label className="form-label">Notiz</label>
        <input type="text" className="form-input" placeholder="optional"
          value={form.notes||''} onChange={e=>set('notes',e.target.value)}/>
        <span className="form-unit"/>
      </div>
      {formExtras}
      {error && (
        <div style={{padding:'10px',background:'var(--danger-bg)',border:'1px solid var(--danger)',borderRadius:8,fontSize:13,color:'var(--danger)',marginBottom:8}}>
          {error}
        </div>
      )}
      <div style={{display:'flex',gap:6,marginTop:8}}>
        <div
          title={usage && !usage.allowed ? `Limit erreicht (${usage.used}/${usage.limit}). Kontaktiere den Admin oder warte bis zum nächsten Reset.` : ''}
          style={{flex:1,display:'inline-block'}}
        >
          <button
            className="btn btn-primary"
            style={{width:'100%', cursor: (usage && !usage.allowed) ? 'not-allowed' : 'pointer'}}
            onClick={onSave}
            disabled={saving || (usage && !usage.allowed)}
          >
            {(usage && !usage.allowed) ? '🔒 Limit erreicht' : saveLabel}
          </button>
        </div>
        {onCancel && <button className="btn btn-secondary" style={{flex:1}} onClick={onCancel}><X size={13}/> Abbrechen</button>}
      </div>
    </div>
  )
}

// ── Main Page ─────────────────────────────────────────────────────────────────
export default function ActivityPage() {
  const [entries,  setEntries]  = useState([])
  const [stats,    setStats]    = useState(null)
  const [tab,      setTab]      = useState('list')
  const [form,     setForm]     = useState(empty())
  const [editing,  setEditing]  = useState(null)
  const [saving,   setSaving]   = useState(false)
  const [saved,    setSaved]    = useState(false)
  const [error,    setError]    = useState(null)
  const [activityUsage, setActivityUsage] = useState(null)  // Phase 4: Usage badge
  const [categories, setCategories] = useState({})  // v9d: Training categories
  const [sessionDetail, setSessionDetail] = useState(null)
  const [metricDraft, setMetricDraft] = useState({})
  const [sessionLoadError, setSessionLoadError] = useState(null)
  const [savingEdit, setSavingEdit] = useState(false)
  const [listLoadingMore, setListLoadingMore] = useState(false)
  const [selectedMonth, setSelectedMonth] = useState(() => ymdMonth())
  const [monthsIncluded, setMonthsIncluded] = useState(() => [ymdMonth()])
  const monthsIncludedRef = useRef(monthsIncluded)

  useEffect(() => {
    monthsIncludedRef.current = monthsIncluded
  }, [monthsIncluded])

  const fetchMonthsChain = useCallback(async (chain) => {
    const lists = await Promise.all(
      chain.map((ym) =>
        api.listActivity(ACTIVITY_MONTH_FETCH_LIMIT, undefined, {
          skipQualityFilter: true,
          collapseDuplicateSessions: true,
          month: ym,
        })
      )
    )
    const merged = dedupeActivitiesById(lists.flat())
    const s = await api.activityStats({ skipQualityFilter: true })
    setEntries(merged)
    setStats(s)
  }, [])

  const load = useCallback(async () => {
    await fetchMonthsChain(monthsIncludedRef.current)
  }, [fetchMonthsChain])

  const onMonthPickerChange = (e) => {
    const ym = e.target.value
    if (!ym) return
    setSelectedMonth(ym)
    const chain = [ym]
    monthsIncludedRef.current = chain
    setMonthsIncluded(chain)
    void fetchMonthsChain(chain)
  }

  const loadPreviousMonth = async () => {
    const chain = monthsIncludedRef.current
    if (chain.length === 0) return
    const oldest = chain[chain.length - 1]
    const prev = prevMonthYm(oldest)
    if (chain.includes(prev)) return
    if (prev < '2000-01') return
    setListLoadingMore(true)
    try {
      const more = await api.listActivity(ACTIVITY_MONTH_FETCH_LIMIT, undefined, {
        skipQualityFilter: true,
        collapseDuplicateSessions: true,
        month: prev,
      })
      const newChain = [...chain, prev]
      monthsIncludedRef.current = newChain
      setMonthsIncluded(newChain)
      setEntries((cur) => dedupeActivitiesById([...cur, ...more]))
    } finally {
      setListLoadingMore(false)
    }
  }

  const oldestLoadedYm = monthsIncluded.length ? monthsIncluded[monthsIncluded.length - 1] : selectedMonth
  const nextOlderYm = prevMonthYm(oldestLoadedYm)
  const canLoadOlder = nextOlderYm >= '2000-01' && !monthsIncluded.includes(nextOlderYm)

  const loadUsage = () => {
    api.getFeatureUsage().then(features => {
      const activityFeature = features.find(f => f.feature_id === 'activity_entries')
      setActivityUsage(activityFeature)
    }).catch(err => console.error('Failed to load usage:', err))
  }

  useEffect(() => {
    const ym = ymdMonth()
    monthsIncludedRef.current = [ym]
    setMonthsIncluded([ym])
    setSelectedMonth(ym)
    void fetchMonthsChain([ym])
    loadUsage()
    api.getTrainingCategories().then(setCategories).catch(err => console.error('Failed to load categories:', err))
  }, [fetchMonthsChain])

  useEffect(() => {
    if (!editing?.id) {
      setSessionDetail(null)
      setMetricDraft({})
      setSessionLoadError(null)
      return
    }
    let cancelled = false
    setSessionLoadError(null)
    ;(async () => {
      try {
        const d = await api.getActivitySession(editing.id)
        if (!cancelled) setSessionDetail(d)
      } catch (err) {
        if (!cancelled) {
          setSessionDetail(null)
          setSessionLoadError(err.message || 'Zusatzfelder konnten nicht geladen werden')
        }
      }
    })()
    return () => { cancelled = true }
  }, [editing?.id])

  useEffect(() => {
    if (!sessionDetail) {
      setMetricDraft({})
      return
    }
    const m = {}
    for (const row of sessionDetail.metrics || []) {
      m[row.key] = row.value
    }
    for (const s of sessionDetail.schema || []) {
      if (!(s.key in m)) {
        m[s.key] = s.data_type === 'boolean' ? false : ''
      }
    }
    setMetricDraft(m)
  }, [sessionDetail])

  const handleSave = async () => {
    setSaving(true)
    setError(null)
    try {
      const payload = {...form}
      payload.start_time =
        payload.start_time === '' || payload.start_time == null
          ? null
          : timePayloadFromInput(payload.start_time)
      payload.end_time =
        payload.end_time === '' || payload.end_time == null
          ? null
          : timePayloadFromInput(payload.end_time)
      if(payload.duration_min) payload.duration_min = parseFloat(payload.duration_min)
      if(payload.kcal_active)  payload.kcal_active  = parseFloat(payload.kcal_active)
      if(payload.hr_avg)       payload.hr_avg       = parseFloat(payload.hr_avg)
      if(payload.hr_max)       payload.hr_max       = parseFloat(payload.hr_max)
      if(payload.rpe)          payload.rpe          = parseInt(payload.rpe)
      payload.source = 'manual'
      await api.createActivity(payload)
      setSaved(true)
      await load()
      await loadUsage()  // Reload usage after save
      setTimeout(()=>{ setSaved(false); setForm(empty()) }, 1500)
    } catch (err) {
      console.error('Save failed:', err)
      setError(err.message || 'Fehler beim Speichern')
      setTimeout(()=>setError(null), 5000)
    } finally {
      setSaving(false)
    }
  }

  const handleUpdate = async () => {
    setSavingEdit(true)
    setError(null)
    try {
      const payload = { ...editing }
      delete payload.id
      for (const s of sessionDetail?.schema || []) {
        const col = s.source_field
        if (!col || !ACTIVITY_LOG_PAYLOAD_KEYS.has(col)) continue
        if (!(s.key in metricDraft)) continue
        const raw = metricDraft[s.key]
        const rawStr = raw === null || raw === undefined ? '' : String(raw).trim()
        if (rawStr === '') {
          payload[col] = null
          continue
        }
        let v = rawStr
        if (s.data_type === 'integer') {
          v = parseInt(rawStr, 10)
          if (Number.isNaN(v)) throw new Error(`Ungültige Zahl: ${s.name_de}`)
        } else if (s.data_type === 'float') {
          v = parseFloat(rawStr)
          if (Number.isNaN(v)) throw new Error(`Ungültige Zahl: ${s.name_de}`)
        } else if (s.data_type === 'boolean') {
          v = !!raw
        } else {
          v = rawStr
        }
        payload[col] = v
      }
      if (payload.duration_min !== '' && payload.duration_min != null) payload.duration_min = parseFloat(payload.duration_min)
      if (payload.kcal_active !== '' && payload.kcal_active != null) payload.kcal_active = parseFloat(payload.kcal_active)
      if (payload.hr_avg !== '' && payload.hr_avg != null) payload.hr_avg = parseFloat(payload.hr_avg)
      if (payload.hr_max !== '' && payload.hr_max != null) payload.hr_max = parseFloat(payload.hr_max)
      if (payload.rpe !== '' && payload.rpe != null) payload.rpe = parseInt(payload.rpe, 10)
      payload.start_time =
        payload.start_time === '' || payload.start_time == null
          ? null
          : timePayloadFromInput(payload.start_time)
      payload.end_time =
        payload.end_time === '' || payload.end_time == null
          ? null
          : timePayloadFromInput(payload.end_time)
      await api.updateActivity(editing.id, payload)
      if (sessionDetail?.schema?.length > 0) {
        const draftForMetrics = { ...metricDraft }
        for (const s of sessionDetail.schema) {
          const bind = activitySchemaHeadlineBinding(s)
          if (!bind || !(s.key in draftForMetrics)) continue
          const rawCol =
            payload[bind.headlineCol] !== undefined ? payload[bind.headlineCol] : editing?.[bind.headlineCol]
          if (rawCol === undefined) continue
          if (s.data_type === 'boolean') {
            draftForMetrics[s.key] = !!rawCol
          } else if (s.data_type === 'integer') {
            const n = parseInt(String(rawCol), 10)
            draftForMetrics[s.key] = Number.isNaN(n) ? '' : n
          } else if (s.data_type === 'float') {
            const n = parseFloat(String(rawCol))
            draftForMetrics[s.key] = Number.isNaN(n) ? '' : n
          } else {
            draftForMetrics[s.key] = rawCol == null ? '' : String(rawCol)
          }
        }
        const metrics = buildMetricsPayload(sessionDetail.schema, draftForMetrics)
        await api.putActivityMetrics(editing.id, { metrics })
      }
      setEditing(null)
      setSessionDetail(null)
      startTransition(() => {
        void load()
      })
    } catch (err) {
      setError(err.message || 'Speichern fehlgeschlagen')
      setTimeout(() => setError(null), 6000)
    } finally {
      setSavingEdit(false)
    }
  }

  const handleDelete = async (id) => {
    if(!confirm('Training löschen?')) return
    await api.deleteActivity(id); await load()
  }

  // Chart data: kcal per day (last 30 days)
  const chartData = (() => {
    const byDate = {}
    entries.forEach(e=>{
      byDate[e.date] = (byDate[e.date]||0) + (e.kcal_active||0)
    })
    return Object.entries(byDate).sort((a,b)=>a[0].localeCompare(b[0])).slice(-30).map(([date,kcal])=>({
      date: dayjs(date).format('DD.MM'), kcal: Math.round(kcal)
    }))
  })()

  const TYPE_COLORS = {
    'Traditionelles Krafttraining':'#1D9E75','Matrial Arts':'#D85A30',
    'Outdoor Spaziergang':'#378ADD','Innenräume Spaziergang':'#7F77DD',
    'Laufen':'#EF9F27','Radfahren':'#D4537E','Sonstiges':'#888780'
  }

  return (
    <div className="capture-page">
      <h1 className="page-title">Aktivität</h1>

      <div className="tabs" style={{overflowX:'auto',flexWrap:'nowrap'}}>
        <button className={'tab'+(tab==='list'?' active':'')} onClick={()=>setTab('list')}>Verlauf</button>
        <button className={'tab'+(tab==='add'?' active':'')} onClick={()=>setTab('add')}>+ Manuell</button>
        <button className={'tab'+(tab==='import'?' active':'')} onClick={()=>setTab('import')}>Import</button>
        <button className={'tab'+(tab==='categorize'?' active':'')} onClick={()=>setTab('categorize')}>Kategorisieren</button>
        <button className={'tab'+(tab==='stats'?' active':'')} onClick={()=>setTab('stats')}>Statistik</button>
      </div>

      {/* Übersicht */}
      {stats && (stats.total_in_profile > 0 || stats.count > 0) && (
        <div className="card section-gap">
          <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 8, lineHeight: 1.45 }}>
            <strong>{stats.total_in_profile ?? '–'}</strong> Einträge im Profil (gleicher Filter wie diese Seite). Die Summen
            Kcal/Stunden beziehen sich auf die <strong>neuesten {stats.sample_size ?? stats.count}</strong> Einträge (max.
            30).
          </div>
          <div style={{display:'flex',gap:8,flexWrap:'wrap'}}>
            {[
              ['Neueste (max. 30)', stats.count, 'var(--text1)'],
              ['Kcal (darin)', Math.round(stats.total_kcal), '#EF9F27'],
              ['Stunden (darin)', Math.round(stats.total_min / 60 * 10) / 10, '#378ADD'],
            ].map(([l, v, c]) => (
              <div key={l} style={{flex:1,minWidth:80,background:'var(--surface2)',borderRadius:8,padding:'8px 10px',textAlign:'center'}}>
                <div style={{fontSize:18,fontWeight:700,color:c}}>{v}</div>
                <div style={{fontSize:10,color:'var(--text3)'}}>{l}</div>
              </div>
            ))}
          </div>
        </div>
      )}

      {tab==='import' && <ImportPanel onImported={load}/>}

      {tab==='categorize' && (
        <div className="card section-gap">
          <div className="card-title">🏷️ Aktivitäten kategorisieren</div>
          <BulkCategorize onComplete={() => { load(); setTab('list'); }} />
        </div>
      )}

      {tab==='add' && (
        <div className="card section-gap">
          <div className="card-title badge-container-right">
            <span>Training eintragen</span>
            {activityUsage && <UsageBadge {...activityUsage} />}
          </div>
          <EntryForm form={form} setForm={setForm}
            onSave={handleSave} saveLabel={saved?'✓ Gespeichert!':'Speichern'}
            saving={saving} error={error} usage={activityUsage}/>
        </div>
      )}

      {tab==='stats' && stats && (
        <div>
          {chartData.length>=2 && (
            <div className="card section-gap">
              <div className="card-title">Aktive Kalorien pro Tag</div>
              <ResponsiveContainer width="100%" height={160}>
                <BarChart data={chartData} margin={{top:4,right:8,bottom:0,left:-20}}>
                  <CartesianGrid stroke="var(--border)" strokeDasharray="3 3"/>
                  <XAxis dataKey="date" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false}
                    interval={Math.max(0,Math.floor(chartData.length/6)-1)}/>
                  <YAxis tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false}/>
                  <Tooltip contentStyle={{background:'var(--surface)',border:'1px solid var(--border)',borderRadius:8,fontSize:11}}
                    formatter={v=>[`${v} kcal`,'Aktiv']}/>
                  <Bar dataKey="kcal" fill="#EF9F27" radius={[3,3,0,0]}/>
                </BarChart>
              </ResponsiveContainer>
            </div>
          )}
          <div className="card section-gap">
            <div className="card-title">Nach Trainingsart</div>
            {Object.entries(stats.by_type).sort((a,b)=>b[1].kcal-a[1].kcal).map(([type,data])=>(
              <div key={type} style={{display:'flex',alignItems:'center',gap:10,padding:'6px 0',borderBottom:'1px solid var(--border)'}}>
                <div style={{width:10,height:10,borderRadius:2,background:TYPE_COLORS[type]||'#888',flexShrink:0}}/>
                <div style={{flex:1,fontSize:13}}>{type}</div>
                <div style={{fontSize:12,color:'var(--text3)'}}>{data.count}× · {Math.round(data.min)} Min · {Math.round(data.kcal)} kcal</div>
              </div>
            ))}
          </div>
        </div>
      )}

      {tab==='list' && (
        <div>
          <div
            style={{
              display: 'flex',
              alignItems: 'center',
              gap: 12,
              marginBottom: 12,
              flexWrap: 'wrap',
            }}
          >
            <label className="form-label" style={{ margin: 0, display: 'flex', alignItems: 'center', gap: 8 }}>
              Monat
              <input
                type="month"
                className="form-input"
                value={selectedMonth}
                onChange={onMonthPickerChange}
                style={{ width: 'auto', minWidth: 150, margin: 0 }}
              />
            </label>
            {monthsIncluded.length > 1 && (
              <span style={{ fontSize: 11, color: 'var(--text3)' }}>
                Zeitraum: {dayjs(`${selectedMonth}-01`).format('MMMM YYYY')} bis{' '}
                {dayjs(`${oldestLoadedYm}-01`).format('MMMM YYYY')}
              </span>
            )}
          </div>
          <p style={{ fontSize: 12, color: 'var(--text3)', margin: '0 0 12px', lineHeight: 1.5 }}>
            Hier sind <strong>alle</strong> Trainings sichtbar (Profil-Qualitätsfilter aus — auch ohne Bewertung oder bei
            abweichender Einordnung). Unter „Verlauf“ / Auswertung bleibt der Filter aktiv. Es wird jeweils ein
            kompletter Kalendermonat geladen; „Vorheriger Monat“ hängt den nächstälteren Monat an (ohne OFFSET-Pagination).
          </p>
          {entries.length===0 && (
            <div className="empty-state">
              <h3>Keine Trainings</h3>
              <p>Importiere deine Apple Health Daten oder trage manuell ein.</p>
            </div>
          )}
          {entries.map(e=>{
            const isEd = editing?.id===e.id
            const color = TYPE_COLORS[e.activity_type]||'#888'
            return (
              <div key={e.id} className="card" style={{marginBottom:8,borderLeft:`3px solid ${color}`}}>
                {isEd ? (
                  <EntryForm
                    form={editing}
                    setForm={setEditing}
                    onSave={handleUpdate}
                    onCancel={() => { setEditing(null); setSessionDetail(null); setSessionLoadError(null) }}
                    saveLabel="Speichern"
                    saving={savingEdit}
                    error={error}
                    formExtras={
                      <>
                        {sessionLoadError && (
                          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 8 }}>{sessionLoadError}</div>
                        )}
                        <SessionMetricsFields
                          schema={sessionDetail?.schema}
                          metrics={sessionDetail?.metrics}
                          values={metricDraft}
                          setValues={setMetricDraft}
                        />
                      </>
                    }
                  />
                ) : (
                  <div>
                    <div style={{display:'flex',justifyContent:'space-between',alignItems:'flex-start'}}>
                      <div style={{flex:1}}>
                        <div style={{display:'flex',alignItems:'center',gap:6,marginBottom:2}}>
                          {/* Evaluation Status Indicator */}
                          {e.quality_label ? (
                            <div
                              style={{
                                display:'inline-flex',
                                alignItems:'center',
                                justifyContent:'center',
                                width:18,
                                height:18,
                                borderRadius:9,
                                background: e.quality_label === 'excellent' || e.quality_label === 'good' ? '#1D9E75' :
                                           e.quality_label === 'acceptable' ? '#EF9F27' : '#D85A30',
                                color:'white',
                                fontSize:10,
                                fontWeight:700,
                                flexShrink:0
                              }}
                              title={`Evaluation: ${e.quality_label} (Score: ${e.overall_score || 'n/a'})`}
                            >
                              ✓
                            </div>
                          ) : e.training_type_id ? (
                            <div
                              style={{
                                display:'inline-flex',
                                alignItems:'center',
                                justifyContent:'center',
                                width:18,
                                height:18,
                                borderRadius:9,
                                background:'#EF9F27',
                                color:'white',
                                fontSize:10,
                                fontWeight:700,
                                flexShrink:0
                              }}
                              title="Trainingstyp zugeordnet, aber nicht evaluiert (kein Profil konfiguriert)"
                            >
                              ⚠
                            </div>
                          ) : (
                            <div
                              style={{
                                display:'inline-flex',
                                alignItems:'center',
                                justifyContent:'center',
                                width:18,
                                height:18,
                                borderRadius:9,
                                background:'#888780',
                                color:'white',
                                fontSize:10,
                                fontWeight:700,
                                flexShrink:0
                              }}
                              title="Kein Trainingstyp zugeordnet"
                            >
                              ✕
                            </div>
                          )}
                          <div style={{fontSize:14,fontWeight:600}}>{e.activity_type}</div>
                          {e.training_category && categories[e.training_category] && (
                            <div style={{
                              display:'inline-flex',
                              alignItems:'center',
                              gap:3,
                              padding:'2px 6px',
                              background:categories[e.training_category].color + '22',
                              border:`1px solid ${categories[e.training_category].color}`,
                              borderRadius:4,
                              fontSize:10,
                              fontWeight:600,
                              color:categories[e.training_category].color
                            }}>
                              <span>{categories[e.training_category].icon}</span>
                              <span>{categories[e.training_category].name_de}</span>
                            </div>
                          )}
                        </div>
                        <div style={{fontSize:11,color:'var(--text3)',marginBottom:4}}>
                          {dayjs(e.date).format('dd, DD. MMMM YYYY')}
                          {(formatTimeForList(e.start_time) || formatTimeForList(e.end_time)) && (
                            <span>
                              {formatTimeForList(e.start_time) && ` · Start ${formatTimeForList(e.start_time)}`}
                              {formatTimeForList(e.end_time) && ` · Ende ${formatTimeForList(e.end_time)}`}
                            </span>
                          )}
                        </div>
                        <div style={{display:'flex',gap:10,flexWrap:'wrap'}}>
                          {e.duration_min && <span style={{fontSize:12,color:'var(--text2)'}}>⏱ {Math.round(e.duration_min)} Min</span>}
                          {e.kcal_active  && <span style={{fontSize:12,color:'#EF9F27'}}>🔥 {Math.round(e.kcal_active)} kcal</span>}
                          {e.hr_avg       && <span style={{fontSize:12,color:'var(--text2)'}}>❤️ Ø{Math.round(e.hr_avg)} bpm</span>}
                          {e.hr_max       && <span style={{fontSize:12,color:'var(--text2)'}}>↑{Math.round(e.hr_max)} bpm</span>}
                          {e.distance_km  && e.distance_km>0 && <span style={{fontSize:12,color:'var(--text2)'}}>📍 {Math.round(e.distance_km*10)/10} km</span>}
                          {e.rpe          && <span style={{fontSize:12,color:'var(--text2)'}}>RPE {e.rpe}/10</span>}
                          {e.source==='apple_health' && <span style={{fontSize:10,color:'var(--text3)'}}>Apple Health</span>}
                        </div>
                        {e.notes && <p style={{fontSize:12,color:'var(--text2)',fontStyle:'italic',marginTop:4}}>"{e.notes}"</p>}
                      </div>
                      <div style={{display:'flex',gap:6,marginLeft:8}}>
                        <button className="btn btn-secondary" style={{padding:'5px 8px'}} onClick={()=>setEditing({...e})}><Pencil size={13}/></button>
                        <button className="btn btn-danger" style={{padding:'5px 8px'}} onClick={()=>handleDelete(e.id)}><Trash2 size={13}/></button>
                      </div>
                    </div>
                  </div>
                )}
              </div>
            )
          })}
          {canLoadOlder && (
            <div style={{ marginTop: 12, marginBottom: 8 }}>
              <button
                type="button"
                className="btn btn-secondary"
                style={{ width: '100%' }}
                disabled={listLoadingMore}
                onClick={() => void loadPreviousMonth()}
              >
                {listLoadingMore
                  ? 'Lade…'
                  : `Vorherigen Monat laden (${dayjs(`${nextOlderYm}-01`).format('MMMM YYYY')})`}
              </button>
            </div>
          )}
        </div>
      )}
    </div>
  )
}
