/**
 * Bearbeitbare Darstellung linearer Progressions-Reihen im Graphen.
 */
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'
import api from '../utils/api'

function emptyNode() {
  return {
    exerciseId: null,
    exerciseTitle: '',
    variantId: null,
    variantName: null,
    variants: [],
  }
}

function chainToDraft(chain) {
  return {
    key: `chain-${chain.edges[0]?.id ?? 'x'}`,
    edgeIds: chain.edges.map((e) => e.id),
    segmentNotes: chain.edges.map((e) => e.notes || ''),
    nodes: chain.nodes.map((n) => ({
      exerciseId: n.exercise_id,
      exerciseTitle: n.title || `Übung #${n.exercise_id}`,
      variantId: n.variant_id ?? null,
      variantName: n.variant_name ?? null,
      variants: [],
    })),
    dirty: false,
    isNew: false,
  }
}

function newChainDraft() {
  const key = `new-${Date.now()}`
  return {
    key,
    edgeIds: [],
    segmentNotes: [],
    nodes: [emptyNode(), emptyNode()],
    dirty: true,
    isNew: true,
  }
}

function formatNodeLabel(node) {
  if (!node.exerciseId) return '— Übung wählen —'
  return (
    <>
      <Link to={`/exercises/${node.exerciseId}`}>{node.exerciseTitle}</Link>
      {node.variantName ? (
        <span style={{ color: 'var(--text3)', fontWeight: 400 }}>{` · ${node.variantName}`}</span>
      ) : null}
    </>
  )
}

const ProgressionChainEditor = forwardRef(function ProgressionChainEditor(
  {
    graphId,
    chains = [],
    busy = false,
    anchorExerciseId = null,
    anchorTitle = null,
    onRefresh,
    onPickExercise,
    loadVariantsForExercise,
    singlePathMode = false,
  },
  ref,
) {
  const [drafts, setDrafts] = useState([])
  const [savingKey, setSavingKey] = useState(null)

  const chainSignature = useMemo(
    () =>
      chains
        .map((c) => c.edges.map((e) => e.id).join(','))
        .join('|'),
    [chains],
  )

  useEffect(() => {
    setDrafts(chains.map(chainToDraft))
  }, [chainSignature, chains])

  const patchDraft = useCallback((key, patchFn) => {
    setDrafts((prev) =>
      prev.map((d) => {
        if (d.key !== key) return d
        const next = patchFn(d)
        return { ...next, dirty: true }
      }),
    )
  }, [])

  const moveNode = (key, idx, dir) => {
    patchDraft(key, (d) => {
      const j = idx + dir
      if (j < 0 || j >= d.nodes.length) return d
      const nodes = [...d.nodes]
      const t = nodes[idx]
      nodes[idx] = nodes[j]
      nodes[j] = t
      return { ...d, nodes }
    })
  }

  const removeNode = (key, idx) => {
    patchDraft(key, (d) => {
      if (d.nodes.length <= 2) return d
      const nodes = d.nodes.filter((_, i) => i !== idx)
      const segmentNotes = d.segmentNotes.slice(0, Math.max(0, nodes.length - 1))
      return { ...d, nodes, segmentNotes }
    })
  }

  const setVariant = (key, idx, variantId) => {
    patchDraft(key, (d) => ({
      ...d,
      nodes: d.nodes.map((n, i) => {
        if (i !== idx) return n
        const v = (n.variants || []).find((x) => Number(x.id) === Number(variantId))
        return {
          ...n,
          variantId: variantId === '' || variantId == null ? null : Number(variantId),
          variantName: v?.variant_name || null,
        }
      }),
    }))
  }

  const applyExerciseToNode = useCallback(async (key, idx, ex) => {
    const title = ex.title || `Übung #${ex.id}`
    const variants =
      Array.isArray(ex.variants) && ex.variants.length
        ? ex.variants
        : await loadVariantsForExercise(ex.id)
    const variantId = ex.exercise_variant_id ?? ex.suggested_variant_id ?? null
    patchDraft(key, (d) => ({
      ...d,
      nodes: d.nodes.map((n, i) =>
        i === idx
          ? {
              exerciseId: ex.id,
              exerciseTitle: title,
              variantId: variantId != null ? Number(variantId) : null,
              variantName:
                variantId != null
                  ? variants.find((v) => Number(v.id) === Number(variantId))?.variant_name || null
                  : null,
              variants,
            }
          : n,
      ),
    }))
  }, [patchDraft, loadVariantsForExercise])

  const insertNodeAfter = (key, idx) => {
    patchDraft(key, (d) => {
      const nodes = [...d.nodes]
      nodes.splice(idx + 1, 0, emptyNode())
      return { ...d, nodes }
    })
    onPickExercise({ kind: 'chain', draftKey: key, nodeIndex: idx + 1 })
  }

  const addNewChain = () => {
    setDrafts((prev) => [...prev, newChainDraft()])
  }

  const discardDraft = (key) => {
    setDrafts((prev) => {
      const draft = prev.find((d) => d.key === key)
      if (!draft) return prev
      if (draft.isNew) return prev.filter((d) => d.key !== key)
      const original = chains.find((c) => `chain-${c.edges[0]?.id}` === key)
      if (!original) return prev.filter((d) => d.key !== key)
      return prev.map((d) => (d.key === key ? chainToDraft(original) : d))
    })
  }

  const deleteChain = async (draft) => {
    if (!graphId) return
    if (draft.isNew) {
      setDrafts((prev) => prev.filter((d) => d.key !== draft.key))
      return
    }
    if (!draft.edgeIds.length) return
    if (!window.confirm(`Reihe mit ${draft.nodes.length} Schritten löschen?`)) return
    setSavingKey(draft.key)
    try {
      await api.deleteExerciseProgressionEdgesBatch(graphId, draft.edgeIds)
      await onRefresh()
    } catch (e) {
      alert(e.message || String(e))
    } finally {
      setSavingKey(null)
    }
  }

  const saveDraft = async (draft) => {
    if (!graphId) return
    const steps = draft.nodes.filter((n) => n.exerciseId != null)
    if (steps.length < 2) {
      alert('Mindestens zwei Schritte mit gewählter Übung.')
      return
    }
    const n = steps.length - 1
    let segment_notes = draft.segmentNotes.slice(0, n)
    while (segment_notes.length < n) segment_notes.push(null)
    segment_notes = segment_notes.slice(0, n)

    setSavingKey(draft.key)
    try {
      if (!draft.isNew && draft.edgeIds.length) {
        await api.deleteExerciseProgressionEdgesBatch(graphId, draft.edgeIds)
      }
      await api.createExerciseProgressionSequence(graphId, {
        steps: steps.map((s) => ({
          exercise_id: s.exerciseId,
          variant_id: s.variantId || null,
        })),
        segment_notes,
      })
      await onRefresh()
    } catch (e) {
      alert(e.message || String(e))
    } finally {
      setSavingKey(null)
    }
  }

  const ensureVariantsLoaded = async (key, idx) => {
    const draft = drafts.find((d) => d.key === key)
    const node = draft?.nodes[idx]
    if (!node?.exerciseId || (node.variants || []).length) return
    const variants = await loadVariantsForExercise(node.exerciseId)
    setDrafts((prev) =>
      prev.map((d) => {
        if (d.key !== key) return d
        return {
          ...d,
          nodes: d.nodes.map((n, i) => (i === idx ? { ...n, variants } : n)),
        }
      }),
    )
  }

  useImperativeHandle(
    ref,
    () => ({
      applyExercise: applyExerciseToNode,
    }),
    [applyExerciseToNode],
  )

  if (!graphId) return null

  return (
    <div style={{ marginBottom: '16px' }}>
      <div
        style={{
          display: 'flex',
          flexWrap: 'wrap',
          gap: '10px',
          alignItems: 'center',
          justifyContent: 'space-between',
          marginBottom: '12px',
        }}
      >
        <div>
          <h4 style={{ margin: 0, fontSize: '0.95rem' }}>
            {singlePathMode ? 'Manuell bearbeiten' : 'Reihen im Graph'}
          </h4>
          <p style={{ fontSize: '12px', color: 'var(--text3)', margin: '4px 0 0', lineHeight: 1.45 }}>
            Schritt 1 → 2 → …: Reihenfolge ändern, Übungen tauschen oder dazwischen einfügen, dann speichern.
          </p>
        </div>
        {!singlePathMode || drafts.length === 0 ? (
          <button type="button" className="btn btn-secondary" disabled={busy} onClick={addNewChain}>
            {singlePathMode ? '+ Pfad anlegen' : '+ Neue Reihe'}
          </button>
        ) : null}
      </div>

      {drafts.length === 0 ? (
        <p style={{ color: 'var(--text2)', margin: 0, fontSize: '13px' }}>
          {singlePathMode
            ? 'Noch kein gespeicherter Pfad — manuell anlegen oder mit dem KI-Planer unten.'
            : 'Noch keine Reihen in diesem Graph.'}
        </p>
      ) : (
        drafts.map((draft, chainIdx) => (
          <div
            key={draft.key}
            style={{
              marginBottom: '16px',
              padding: '14px',
              borderRadius: '10px',
              border: `1px solid ${
                draft.dirty
                  ? 'color-mix(in srgb, var(--accent) 50%, var(--border))'
                  : 'var(--border)'
              }`,
              background: 'var(--surface2)',
            }}
          >
            <div
              style={{
                display: 'flex',
                flexWrap: 'wrap',
                gap: '8px',
                alignItems: 'center',
                marginBottom: '12px',
              }}
            >
              <strong style={{ fontSize: '13px' }}>
                {singlePathMode ? 'Gespeicherter Pfad' : `Reihe ${chainIdx + 1}`}
              </strong>
              {draft.dirty ? (
                <span className="exercise-tag" style={{ borderColor: 'var(--accent)' }}>
                  Ungespeichert
                </span>
              ) : null}
              {draft.isNew ? (
                <span className="exercise-tag">Neu</span>
              ) : (
                <span className="exercise-tag">{draft.nodes.length} Schritte</span>
              )}
            </div>

            <div style={{ display: 'flex', flexDirection: 'column', gap: '0' }}>
              {draft.nodes.map((node, idx) => (
                <React.Fragment key={`${draft.key}-node-${idx}`}>
                  {idx > 0 ? (
                    <div
                      style={{
                        display: 'flex',
                        alignItems: 'center',
                        gap: '8px',
                        padding: '4px 0 4px 12px',
                        color: 'var(--accent)',
                        fontSize: '12px',
                        fontWeight: 700,
                      }}
                      aria-hidden
                    >
                      ↓ Nachfolger
                    </div>
                  ) : null}
                  <div
                    style={{
                      display: 'grid',
                      gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))',
                      gap: '10px',
                      alignItems: 'end',
                      padding: '10px 12px',
                      borderRadius: '8px',
                      border: '1px solid var(--border)',
                      background: 'var(--surface)',
                    }}
                  >
                    <div className="form-row" style={{ marginBottom: 0 }}>
                      <label className="form-label">Schritt {idx + 1}</label>
                      <div
                        style={{
                          display: 'flex',
                          flexWrap: 'wrap',
                          gap: '8px',
                          alignItems: 'center',
                        }}
                      >
                        <span style={{ fontSize: '13px', flex: '1 1 140px' }}>
                          {formatNodeLabel(node)}
                        </span>
                        <button
                          type="button"
                          className="btn btn-secondary"
                          style={{ fontSize: '12px', padding: '4px 10px' }}
                          disabled={busy || savingKey === draft.key}
                          onClick={() =>
                            onPickExercise({ kind: 'chain', draftKey: draft.key, nodeIndex: idx })
                          }
                        >
                          {node.exerciseId ? 'Tauschen…' : 'Übung…'}
                        </button>
                        {anchorExerciseId != null ? (
                          <button
                            type="button"
                            className="btn"
                            style={{ fontSize: '12px', padding: '4px 10px' }}
                            disabled={busy || savingKey === draft.key}
                            onClick={async () => {
                              const variants = await loadVariantsForExercise(anchorExerciseId)
                              await applyExerciseToNode(draft.key, idx, {
                                id: anchorExerciseId,
                                title: anchorTitle?.trim() || `Übung #${anchorExerciseId}`,
                                variants,
                              })
                            }}
                          >
                            Kontext-Übung
                          </button>
                        ) : null}
                      </div>
                    </div>
                    <div className="form-row" style={{ marginBottom: 0 }}>
                      <label className="form-label">Variante</label>
                      <select
                        className="form-input"
                        disabled={!node.exerciseId || busy || savingKey === draft.key}
                        value={node.variantId ?? ''}
                        onFocus={() => ensureVariantsLoaded(draft.key, idx)}
                        onChange={(e) =>
                          setVariant(
                            draft.key,
                            idx,
                            e.target.value === '' ? null : parseInt(e.target.value, 10),
                          )
                        }
                      >
                        <option value="">Gesamte Übung</option>
                        {(node.variants || []).map((v) => (
                          <option key={v.id} value={v.id}>
                            {v.variant_name || `Variante #${v.id}`}
                          </option>
                        ))}
                      </select>
                    </div>
                    <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
                      <button
                        type="button"
                        className="btn"
                        style={{ fontSize: '12px', padding: '4px 8px' }}
                        disabled={busy || savingKey === draft.key || idx === 0}
                        onClick={() => moveNode(draft.key, idx, -1)}
                      >
                        ↑
                      </button>
                      <button
                        type="button"
                        className="btn"
                        style={{ fontSize: '12px', padding: '4px 8px' }}
                        disabled={busy || savingKey === draft.key || idx >= draft.nodes.length - 1}
                        onClick={() => moveNode(draft.key, idx, 1)}
                      >
                        ↓
                      </button>
                      <button
                        type="button"
                        className="btn"
                        style={{ fontSize: '12px', padding: '4px 8px' }}
                        disabled={busy || savingKey === draft.key}
                        onClick={() => insertNodeAfter(draft.key, idx)}
                      >
                        + Einfügen
                      </button>
                      <button
                        type="button"
                        className="btn"
                        style={{ fontSize: '12px', padding: '4px 8px' }}
                        disabled={busy || savingKey === draft.key || draft.nodes.length <= 2}
                        onClick={() => removeNode(draft.key, idx)}
                      >
                        Entfernen
                      </button>
                    </div>
                  </div>
                </React.Fragment>
              ))}
            </div>

            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', marginTop: '12px' }}>
              <button
                type="button"
                className="btn btn-primary"
                disabled={busy || savingKey === draft.key || !draft.dirty}
                onClick={() => saveDraft(draft)}
              >
                {savingKey === draft.key ? 'Speichern …' : singlePathMode ? 'Pfad speichern' : 'Reihe speichern'}
              </button>
              {draft.dirty ? (
                <button
                  type="button"
                  className="btn btn-secondary"
                  disabled={busy || savingKey === draft.key}
                  onClick={() => discardDraft(draft.key)}
                >
                  Verwerfen
                </button>
              ) : null}
              <button
                type="button"
                className="btn"
                style={{
                  fontSize: '12px',
                  background: 'var(--danger)',
                  color: '#fff',
                  border: 'none',
                }}
                disabled={busy || savingKey === draft.key}
                onClick={() => deleteChain(draft)}
              >
                {singlePathMode ? 'Pfad löschen' : 'Reihe löschen'}
              </button>
            </div>
          </div>
        ))
      )}
    </div>
  )
})

export default ProgressionChainEditor
