import { useCallback, useEffect, useMemo, useState } from 'react'
import { ChevronDown, ChevronUp, LayoutGrid } from 'lucide-react'
import { Link } from 'react-router-dom'
import { api, formatFastApiDetail } from '../utils/api'
import { WidgetRenderer } from '../widgetSystem/dashboardWidgetRegistry'
import { ensurePilotLabWidgetsRegistered } from '../widgetSystem/registerPilotLabWidgets'
import {
  BODY_CHART_DAYS_DEFAULT,
  BODY_CHART_DAYS_MAX,
  BODY_CHART_DAYS_MIN,
  normalizeBodyChartDays,
} from '../widgetSystem/bodyChartDays'
import KpiBoardConfigEditor from '../widgetSystem/KpiBoardConfigEditor'
import QuickCaptureConfigEditor from '../widgetSystem/QuickCaptureConfigEditor'
import { moveWidget, normalizeLayoutForEditor, toggleWidget } from '../widgetSystem/layoutEditor'

/** Widgets mit optionalem config.chart_days (7–90), gleiche UX im Editor */
const CHART_DAYS_WIDGET_IDS = new Set([
  'body_overview',
  'activity_overview',
  'nutrition_detail_charts',
  'recovery_charts_panel',
])

function catalogMetaById(catalog) {
  if (!catalog?.widgets?.length) return {}
  return Object.fromEntries(catalog.widgets.map((w) => [w.id, w]))
}

export default function DashboardLabPage() {
  ensurePilotLabWidgetsRegistered()

  const [refreshTick, setRefreshTick] = useState(0)
  const requestRefresh = () => setRefreshTick((t) => t + 1)
  const [catalog, setCatalog] = useState(null)
  const [bundle, setBundle] = useState(null)
  const [layout, setLayout] = useState(null)
  const [err, setErr] = useState(null)
  const [busy, setBusy] = useState(false)
  const [msg, setMsg] = useState(null)
  /** Pro Widget-ID: Rohstring während der Eingabe (Tippen ohne sofortiges Clampen) */
  const [chartDaysDraftByWidgetId, setChartDaysDraftByWidgetId] = useState({})

  const metaById = catalogMetaById(catalog)

  const isWidgetCatalogAllowed = useCallback(
    (widgetId) => {
      const m = metaById[widgetId]
      if (m == null) return true
      return m.allowed !== false
    },
    [metaById],
  )

  const visibleEditorIndices = useMemo(
    () =>
      layout?.widgets?.map((_, i) => i).filter((i) => isWidgetCatalogAllowed(layout.widgets[i].id)) ?? [],
    [layout, isWidgetCatalogAllowed],
  )

  const layoutForPreview = useMemo(
    () =>
      layout
        ? {
            ...layout,
            widgets: layout.widgets.map((w) => ({
              ...w,
              enabled: w.enabled && isWidgetCatalogAllowed(w.id),
            })),
          }
        : null,
    [layout, isWidgetCatalogAllowed],
  )

  const commitChartDaysDraftToLayout = useCallback((draftStr, baseLayout, widgetId) => {
    const clamped = normalizeBodyChartDays(
      draftStr === '' || draftStr == null ? BODY_CHART_DAYS_DEFAULT : draftStr
    )
    return {
      ...baseLayout,
      widgets: baseLayout.widgets.map((x) =>
        x.id !== widgetId ? x : { ...x, config: { ...x.config, chart_days: clamped } }
      ),
    }
  }, [])

  const load = useCallback(async () => {
    setErr(null)
    try {
      const [cat, b] = await Promise.all([api.getAppWidgetsCatalog(), api.getAppDashboardLayout()])
      setCatalog(cat)
      setBundle(b)
      setChartDaysDraftByWidgetId({})
      setLayout(normalizeLayoutForEditor(b.layout))
    } catch (e) {
      setErr(formatFastApiDetail(null, e.message))
    }
  }, [])

  useEffect(() => {
    load()
  }, [load])

  const save = async () => {
    if (!layout) return
    let toSave = layout
    const draftEntries = Object.entries(chartDaysDraftByWidgetId)
    if (draftEntries.length) {
      for (const [wid, val] of draftEntries) {
        toSave = normalizeLayoutForEditor(commitChartDaysDraftToLayout(val, toSave, wid))
      }
      setLayout(toSave)
      setChartDaysDraftByWidgetId({})
    }
    setBusy(true)
    setMsg(null)
    setErr(null)
    try {
      await api.putAppDashboardLayout(toSave)
      setMsg('Layout gespeichert.')
      await load()
    } catch (e) {
      setErr(formatFastApiDetail(null, e.message))
    } finally {
      setBusy(false)
    }
  }

  const reset = async () => {
    if (!confirm('Persönliches Layout löschen und Standard wiederherstellen?')) return
    setBusy(true)
    setMsg(null)
    setErr(null)
    try {
      const r = await api.resetAppDashboardLayout()
      setChartDaysDraftByWidgetId({})
      setLayout(normalizeLayoutForEditor(r.layout))
      setMsg('Auf Standard zurückgesetzt.')
      await load()
    } catch (e) {
      setErr(formatFastApiDetail(null, e.message))
    } finally {
      setBusy(false)
    }
  }

  const applyDefaultLocal = () => {
    if (bundle?.lab_default_layout) {
      setChartDaysDraftByWidgetId({})
      setLayout(normalizeLayoutForEditor(structuredClone(bundle.lab_default_layout)))
      setMsg('Lab-Standard geladen (noch nicht gespeichert).')
    }
  }

  if (err && !layout) {
    return (
      <div style={{ padding: 24, maxWidth: 640, margin: '0 auto' }}>
        <p style={{ color: '#D85A30' }}>{err}</p>
        <button type="button" className="btn btn-secondary" onClick={load}>
          Erneut laden
        </button>
      </div>
    )
  }

  if (!layout) {
    return (
      <div style={{ padding: 48, textAlign: 'center' }}>
        <div className="spinner" style={{ width: 32, height: 32, margin: '0 auto' }} />
      </div>
    )
  }

  return (
    <div style={{ paddingBottom: 96, textAlign: 'left', maxWidth: 920, margin: '0 auto' }}>
      <div style={{ marginBottom: 20 }}>
        <Link
          to="/settings"
          className="btn btn-secondary"
          style={{ display: 'inline-flex', marginBottom: 12, textDecoration: 'none' }}
        >
          ← Einstellungen
        </Link>
        <h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <LayoutGrid size={26} color="var(--accent)" />
          App-Bereich: Dashboard-Lab
        </h1>
        <p style={{ fontSize: 13, color: 'var(--text2)', lineHeight: 1.6, marginTop: 8 }}>
          Widget-System: Katalog, Registry, Renderer; optional pro Widget <code>config</code> (z. B.{' '}
          <strong>Körper</strong> / <strong>Aktivität</strong>: Zeitraum 7–90 Tage; <strong>KPI</strong>: Kacheln
          wählen &amp; sortieren). Layout pro Profil in der DB —
          getrennt vom Produktiv-Dashboard.
          Vergleich:{' '}
          <Link to="/pilot/viz" style={{ color: 'var(--accent)' }}>
            Pilot-Übersicht (festes Standard-Layout)
          </Link>
          .
        </p>
      </div>

      <div
        className="card"
        style={{
          marginBottom: 20,
          borderStyle: 'dashed',
          borderColor: 'var(--border2)',
          background: 'var(--surface2)',
        }}
      >
        <div className="card-title" style={{ fontSize: 14 }}>
          Layout (v1)
        </div>
        {bundle && (
          <p style={{ fontSize: 12, color: 'var(--text2)', marginBottom: 12 }}>
            Status: {bundle.custom ? 'individuell gespeichert' : 'Standard (nicht in DB)'}
          </p>
        )}
        {err && <p style={{ fontSize: 12, color: '#D85A30', marginBottom: 8 }}>{err}</p>}
        {msg && <p style={{ fontSize: 12, color: 'var(--accent)', marginBottom: 8 }}>{msg}</p>}
        <ul style={{ listStyle: 'none', padding: 0, margin: '0 0 12px' }}>
          {visibleEditorIndices.map((i) => {
            const w = layout.widgets[i]
            const label = metaById[w.id]?.title || w.id
            const chartDaysVal =
              w.config?.chart_days != null
                ? normalizeBodyChartDays(w.config.chart_days)
                : BODY_CHART_DAYS_DEFAULT
            return (
              <li
                key={w.id}
                style={{
                  padding: '8px 0',
                  borderBottom: '1px solid var(--border)',
                }}
              >
                <div
                  style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 8,
                    flexWrap: 'wrap',
                  }}
                >
                  <label style={{ display: 'flex', alignItems: 'center', gap: 8, flex: '1 1 140px' }}>
                    <input
                      type="checkbox"
                      checked={w.enabled}
                      onChange={() => setLayout((L) => toggleWidget(L, i))}
                    />
                    <span style={{ fontSize: 14 }}>{label}</span>
                  </label>
                  <div style={{ display: 'flex', gap: 6 }}>
                    <button
                      type="button"
                      className="btn btn-secondary"
                      style={{ padding: '6px 10px' }}
                      aria-label="Nach oben"
                      onClick={() => setLayout((L) => moveWidget(L, i, -1))}
                    >
                      <ChevronUp size={18} />
                    </button>
                    <button
                      type="button"
                      className="btn btn-secondary"
                      style={{ padding: '6px 10px' }}
                      aria-label="Nach unten"
                      onClick={() => setLayout((L) => moveWidget(L, i, 1))}
                    >
                      <ChevronDown size={18} />
                    </button>
                  </div>
                </div>
                {w.id === 'quick_capture' && (
                  <QuickCaptureConfigEditor
                    config={w.config || {}}
                    onChange={(next) =>
                      setLayout((L) =>
                        normalizeLayoutForEditor({
                          ...L,
                          widgets: L.widgets.map((x, j) => {
                            if (j !== i) return x
                            const cfg = { ...(x.config || {}) }
                            for (const k of ['show_weight', 'show_resting_hr', 'show_hrv', 'show_vo2_max']) {
                              delete cfg[k]
                            }
                            Object.assign(cfg, next)
                            return { ...x, config: cfg }
                          }),
                        })
                      )
                    }
                  />
                )}
                {w.id === 'kpi_board' && (
                  <KpiBoardConfigEditor
                    tiles={Object.prototype.hasOwnProperty.call(w.config || {}, 'tiles') ? w.config.tiles : undefined}
                    onChange={(next) =>
                      setLayout((L) =>
                        normalizeLayoutForEditor({
                          ...L,
                          widgets: L.widgets.map((x, j) => {
                            if (j !== i) return x
                            const cfg = { ...(x.config || {}) }
                            if (next === undefined) {
                              delete cfg.tiles
                            } else {
                              cfg.tiles = next
                            }
                            return { ...x, config: cfg }
                          }),
                        })
                      )
                    }
                  />
                )}
                {CHART_DAYS_WIDGET_IDS.has(w.id) && (
                  <div style={{ marginTop: 10, marginLeft: 28 }}>
                    <label style={{ fontSize: 12, color: 'var(--text2)', display: 'block', marginBottom: 4 }}>
                      {w.id === 'body_overview'
                        ? 'Körper-Chart'
                        : w.id === 'activity_overview'
                          ? 'Aktivität (Verteilung & Konsistenz)'
                          : w.id === 'nutrition_detail_charts'
                            ? 'Ernährung — Charts'
                            : 'Erholung — Charts'}{' '}
                      — Zeitraum (Tage): {BODY_CHART_DAYS_MIN}–{BODY_CHART_DAYS_MAX}
                    </label>
                    <input
                      type="text"
                      inputMode="numeric"
                      autoComplete="off"
                      className="form-input"
                      style={{ maxWidth: 120 }}
                      aria-label={
                        w.id === 'body_overview'
                          ? 'Körper-Chart Zeitraum in Tagen'
                          : w.id === 'activity_overview'
                            ? 'Aktivität Zeitraum in Tagen'
                            : w.id === 'nutrition_detail_charts'
                              ? 'Ernährungs-Charts Zeitraum in Tagen'
                              : 'Erholungs-Charts Zeitraum in Tagen'
                      }
                      value={
                        chartDaysDraftByWidgetId[w.id] !== undefined
                          ? chartDaysDraftByWidgetId[w.id]
                          : String(chartDaysVal)
                      }
                      onFocus={() =>
                        setChartDaysDraftByWidgetId((prev) => ({
                          ...prev,
                          [w.id]: String(chartDaysVal),
                        }))
                      }
                      onChange={(e) =>
                        setChartDaysDraftByWidgetId((prev) => ({
                          ...prev,
                          [w.id]: e.target.value,
                        }))
                      }
                      onBlur={(e) => {
                        const raw = e.target.value
                        setLayout((L) =>
                          normalizeLayoutForEditor(commitChartDaysDraftToLayout(raw, L, w.id))
                        )
                        setChartDaysDraftByWidgetId((prev) => {
                          const next = { ...prev }
                          delete next[w.id]
                          return next
                        })
                      }}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter') e.currentTarget.blur()
                      }}
                    />
                  </div>
                )}
              </li>
            )
          })}
        </ul>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
          <button type="button" className="btn btn-primary" disabled={busy} onClick={save}>
            Speichern
          </button>
          <button type="button" className="btn btn-secondary" disabled={busy} onClick={reset}>
            Zurücksetzen (DB)
          </button>
          <button type="button" className="btn btn-secondary" disabled={busy} onClick={applyDefaultLocal}>
            Standard in Editor laden
          </button>
        </div>
      </div>

      {layoutForPreview && (
        <WidgetRenderer layout={layoutForPreview} refreshTick={refreshTick} requestRefresh={requestRefresh} />
      )}
    </div>
  )
}
