/**
 * Progressionsgraphen — Kachel-Übersicht (wie Übungen) + Editor-Detailansicht.
 */
import React, {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useState,
} from 'react'
import { Link, useLocation } from 'react-router-dom'
import api from '../utils/api'
import SkillProfilePanel from './skills/SkillProfilePanel'
import { useAuth } from '../context/AuthContext'
import { activeClubMemberships, getTenantClubDependencyKey } from '../utils/activeClub'
import ProgressionGraphEditor from './ProgressionGraphEditor'
import ProgressionGraphListCard from './ProgressionGraphListCard'
import { EXERCISE_VISIBILITY_FIELD_LABEL } from '../constants/exerciseGovernanceLabels'

const VIS_OPTIONS = [
  { value: 'private', label: 'Privat' },
  { value: 'club', label: 'Verein' },
  { value: 'official', label: 'Offiziell' },
]

function edgeTypeLabel(type) {
  if (type === 'next_exercise') return 'Nachfolger'
  if (type === 'sibling') return 'Schwester'
  return type || '—'
}

function ExerciseProgressionGraphPanel(
  {
    anchorExerciseId = null,
    anchorTitle = null,
    initialGraphId = null,
  },
  ref,
) {
  const { user } = useAuth()
  const location = useLocation()
  const isSuperadmin = user?.role === 'superadmin'
  const tenantClubDepKey = useMemo(() => getTenantClubDependencyKey(user), [user])

  const filteredGraphVisOptions = useMemo(
    () => VIS_OPTIONS.filter((o) => o.value !== 'official' || isSuperadmin),
    [isSuperadmin],
  )

  const [graphs, setGraphs] = useState([])
  const [selectedGraphId, setSelectedGraphId] = useState(null)
  const [edges, setEdges] = useState([])
  const [busy, setBusy] = useState(false)
  const [loadErr, setLoadErr] = useState(null)

  const [createModalOpen, setCreateModalOpen] = useState(false)
  const [newGraphName, setNewGraphName] = useState('')
  const [newGraphVisibility, setNewGraphVisibility] = useState('private')

  const [metaName, setMetaName] = useState('')
  const [metaDescription, setMetaDescription] = useState('')
  const [metaVisibility, setMetaVisibility] = useState('private')

  const [filterAnchorOnly, setFilterAnchorOnly] = useState(!!anchorExerciseId)
  const [editingEdgeNotes, setEditingEdgeNotes] = useState(null)
  const [notesDraft, setNotesDraft] = useState('')
  const [skillProfileData, setSkillProfileData] = useState(null)
  const [skillProfileLoading, setSkillProfileLoading] = useState(false)
  const [skillProfileError, setSkillProfileError] = useState('')

  useImperativeHandle(ref, () => ({
    openCreateDialog: () => {
      setNewGraphName('')
      setNewGraphVisibility('private')
      setCreateModalOpen(true)
    },
  }))

  useEffect(() => {
    const gid =
      initialGraphId ??
      location.state?.progressionGraphId
    if (gid != null && Number.isFinite(Number(gid))) {
      setSelectedGraphId(Number(gid))
    }
  }, [location.state?.progressionGraphId, initialGraphId])

  useEffect(() => {
    if (!initialGraphId && !location.state?.progressionGraphId) {
      setSelectedGraphId(null)
    }
  }, [tenantClubDepKey, initialGraphId, location.state?.progressionGraphId])

  const refreshGraphs = useCallback(async () => {
    const list = await api.listExerciseProgressionGraphs()
    setGraphs(Array.isArray(list) ? list : [])
    return list
  }, [])

  const refreshEdges = useCallback(async (gid) => {
    if (!gid) {
      setEdges([])
      return
    }
    const list = await api.listExerciseProgressionEdges(gid)
    setEdges(Array.isArray(list) ? list : [])
  }, [])

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setBusy(true)
      setLoadErr(null)
      try {
        await refreshGraphs()
      } catch (e) {
        if (!cancelled) setLoadErr(e.message || String(e))
      } finally {
        if (!cancelled) setBusy(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [refreshGraphs, tenantClubDepKey])

  useEffect(() => {
    if (!selectedGraphId) {
      setSkillProfileData(null)
      return undefined
    }
    let cancelled = false
    ;(async () => {
      setSkillProfileLoading(true)
      setSkillProfileError('')
      try {
        const data = await api.getProgressionGraphSkillProfile(selectedGraphId)
        if (!cancelled) setSkillProfileData(data)
      } catch (e) {
        if (!cancelled) {
          setSkillProfileData(null)
          setSkillProfileError(e.message || 'Fähigkeiten-Profil nicht geladen')
        }
      } finally {
        if (!cancelled) setSkillProfileLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [selectedGraphId, edges.length])

  useEffect(() => {
    if (!selectedGraphId) {
      setEdges([])
      setMetaName('')
      setMetaDescription('')
      setMetaVisibility('private')
      return
    }
    const g = graphs.find((x) => x.id === selectedGraphId)
    if (g) {
      setMetaName(g.name || '')
      setMetaDescription(g.description || '')
      setMetaVisibility(g.visibility || 'private')
    }
    let cancelled = false
    ;(async () => {
      try {
        await refreshEdges(selectedGraphId)
      } catch (e) {
        if (!cancelled) alert(e.message || String(e))
      }
    })()
    return () => {
      cancelled = true
    }
  }, [selectedGraphId, graphs, refreshEdges])

  const filteredEdges = useMemo(() => {
    if (!filterAnchorOnly || anchorExerciseId == null) return edges
    return edges.filter(
      (e) =>
        e.from_exercise_id === anchorExerciseId || e.to_exercise_id === anchorExerciseId,
    )
  }, [edges, filterAnchorOnly, anchorExerciseId])

  const handleCreateGraph = async (e) => {
    e.preventDefault()
    const name = newGraphName.trim()
    if (!name) {
      alert('Name für den Graphen eingeben')
      return
    }
    setBusy(true)
    try {
      const created = await api.createExerciseProgressionGraph({
        name,
        visibility: newGraphVisibility,
      })
      setCreateModalOpen(false)
      setNewGraphName('')
      await refreshGraphs()
      if (created?.id != null) setSelectedGraphId(created.id)
    } catch (err) {
      alert(err.message || String(err))
    } finally {
      setBusy(false)
    }
  }

  const handleDeleteGraph = async (graph) => {
    const gid = graph?.id ?? selectedGraphId
    if (!gid) return
    if (!window.confirm(`Progressionsgraph „${graph?.name || gid}" wirklich löschen?`)) return
    setBusy(true)
    try {
      await api.deleteExerciseProgressionGraph(gid)
      if (selectedGraphId === gid) setSelectedGraphId(null)
      await refreshGraphs()
    } catch (err) {
      alert(err.message || String(err))
    } finally {
      setBusy(false)
    }
  }

  const resolvePromoteClubId = () => {
    const g = graphs.find((x) => x.id === selectedGraphId)
    if (g?.club_id != null) return Number(g.club_id)
    const memberships = activeClubMemberships(user?.clubs)
    const active = memberships.find((c) => c.is_active) || memberships[0]
    return active?.club_id != null ? Number(active.club_id) : null
  }

  const handleSaveMeta = async () => {
    if (!selectedGraphId) return
    const name = metaName.trim()
    if (!name) {
      alert('Name ist Pflicht')
      return
    }
    const prevGraph = graphs.find((x) => x.id === selectedGraphId)
    const prevVis = (prevGraph?.visibility || 'private').trim().toLowerCase()
    const nextVis = (metaVisibility || 'private').trim().toLowerCase()

    setBusy(true)
    try {
      if (prevVis === 'private' && nextVis === 'club') {
        const preview = await api.getProgressionGraphVisibilityPromotionCandidates(
          selectedGraphId,
          { targetVisibility: 'club' },
        )
        const privateExercises = Array.isArray(preview?.exercises) ? preview.exercises : []
        if (privateExercises.length > 0) {
          const titles = privateExercises
            .slice(0, 8)
            .map((ex) => `• ${ex.title || `Übung #${ex.id}`}`)
            .join('\n')
          const more =
            privateExercises.length > 8
              ? `\n… und ${privateExercises.length - 8} weitere`
              : ''
          const promote = window.confirm(
            `Der Graph wird auf „Verein“ gestellt. Im Graph sind noch ${privateExercises.length} private Übung(en):\n\n${titles}${more}\n\nDiese Übungen ebenfalls auf Vereins-Sichtbarkeit anheben?`,
          )
          if (promote) {
            const clubId = resolvePromoteClubId()
            if (!clubId) {
              alert('Kein aktiver Verein — Übungen können nicht auf Verein promoted werden.')
            } else {
              const ids = privateExercises.map((ex) => ex.id).filter((id) => id != null)
              const res = await api.bulkPatchExercisesMetadata({
                exercise_ids: ids,
                visibility: 'club',
                club_id: clubId,
              })
              if ((res?.failed || []).length) {
                const f = res.failed[0]
                throw new Error(f?.detail || 'Übungs-Promotion fehlgeschlagen')
              }
            }
          }
        }
      }

      await api.updateExerciseProgressionGraph(selectedGraphId, {
        name,
        description: metaDescription.trim() || null,
        visibility: metaVisibility,
      })
      await refreshGraphs()
      alert('Graph-Metadaten gespeichert.')
    } catch (err) {
      alert(err.message || String(err))
    } finally {
      setBusy(false)
    }
  }

  const handleDeleteEdge = async (edgeId) => {
    if (!selectedGraphId) return
    setBusy(true)
    try {
      await api.deleteExerciseProgressionEdge(selectedGraphId, edgeId)
      await refreshEdges(selectedGraphId)
    } catch (err) {
      alert(err.message || String(err))
    } finally {
      setBusy(false)
    }
  }

  const startEditNotes = (edge) => {
    setEditingEdgeNotes(edge.id)
    setNotesDraft(edge.notes || '')
  }

  const saveNotes = async (edgeId) => {
    if (!selectedGraphId) return
    setBusy(true)
    try {
      await api.updateExerciseProgressionEdge(selectedGraphId, edgeId, {
        notes: notesDraft.trim() || null,
      })
      setEditingEdgeNotes(null)
      await refreshEdges(selectedGraphId)
    } catch (err) {
      alert(err.message || String(err))
    } finally {
      setBusy(false)
    }
  }

  const handleEditorSaved = useCallback(async () => {
    if (!selectedGraphId) return
    await Promise.all([refreshEdges(selectedGraphId), refreshGraphs()])
  }, [selectedGraphId, refreshEdges, refreshGraphs])

  const selectedGraph = graphs.find((g) => g.id === selectedGraphId)

  if (loadErr) {
    return (
      <div className="card" style={{ borderColor: 'var(--danger)' }}>
        <p style={{ margin: 0, color: 'var(--danger)' }}>{loadErr}</p>
      </div>
    )
  }

  if (!selectedGraphId) {
    return (
      <div className="exercise-progression-panel">
        {anchorExerciseId != null && (
          <p style={{ fontSize: '13px', color: 'var(--text2)', marginBottom: '12px' }}>
            Kontext:{' '}
            <strong>{anchorTitle?.trim() || `Übung #${anchorExerciseId}`}</strong>
            {' · '}
            <Link to={`/exercises/${anchorExerciseId}`}>Ansehen</Link>
          </p>
        )}

        <p style={{ fontSize: '13px', color: 'var(--text2)', marginBottom: '16px' }}>
          Progressionsgraphen planen didaktische Entwicklungspfade mit Roadmap-Slots, KI-Match und
          Bewertung — analog zur Übungsbibliothek als eigene Sammlung.
        </p>

        {busy && graphs.length === 0 ? (
          <div className="empty-state card" style={{ padding: '2rem 1rem' }}>
            <div className="spinner" />
            <p className="muted" style={{ marginTop: '12px' }}>
              Lade Progressionsgraphen…
            </p>
          </div>
        ) : graphs.length === 0 ? (
          <div className="card empty-state" style={{ padding: '2rem 1rem', textAlign: 'center' }}>
            <p style={{ margin: '0 0 12px', color: 'var(--text2)' }}>
              Noch keine Progressionsgraphen — lege den ersten an.
            </p>
            <button
              type="button"
              className="btn btn-primary"
              onClick={() => {
                setCreateModalOpen(true)
              }}
            >
              + Neu
            </button>
          </div>
        ) : (
          <div className="exercises-list-grid">
            {graphs.map((g) => (
              <ProgressionGraphListCard
                key={g.id}
                graph={g}
                userId={user?.id}
                disabled={busy}
                onOpen={(row) => setSelectedGraphId(row.id)}
                onDelete={handleDeleteGraph}
              />
            ))}
          </div>
        )}

        {createModalOpen ? (
          <div
            className="admin-modal-backdrop"
            role="presentation"
            onClick={(e) => {
              if (e.target === e.currentTarget && !busy) setCreateModalOpen(false)
            }}
          >
            <div
              className="admin-modal-sheet"
              role="dialog"
              aria-modal="true"
              aria-labelledby="new-progression-graph-title"
              onClick={(e) => e.stopPropagation()}
              style={{ maxWidth: '480px' }}
            >
              <div className="admin-modal-sheet__header">
                <h3 id="new-progression-graph-title" className="admin-modal-sheet__title">
                  Neuer Progressionsgraph
                </h3>
                <button
                  type="button"
                  className="btn btn-secondary admin-modal-sheet__close"
                  disabled={busy}
                  onClick={() => setCreateModalOpen(false)}
                >
                  Schließen
                </button>
              </div>
              <form onSubmit={handleCreateGraph}>
                <div className="admin-modal-sheet__body">
                  <div className="form-row">
                    <label className="form-label">Name *</label>
                    <input
                      className="form-input"
                      value={newGraphName}
                      onChange={(e) => setNewGraphName(e.target.value)}
                      placeholder="z. B. Kumite-Einstieg Verein Nord"
                      autoFocus
                    />
                  </div>
                  <div className="form-row">
                    <label className="form-label">{EXERCISE_VISIBILITY_FIELD_LABEL}</label>
                    <select
                      className="form-input"
                      value={newGraphVisibility}
                      onChange={(e) => setNewGraphVisibility(e.target.value)}
                    >
                      {filteredGraphVisOptions.map((o) => (
                        <option key={o.value} value={o.value}>
                          {o.label}
                        </option>
                      ))}
                    </select>
                  </div>
                </div>
                <div className="admin-modal-sheet__footer">
                  <button type="button" className="btn btn-secondary" disabled={busy} onClick={() => setCreateModalOpen(false)}>
                    Abbrechen
                  </button>
                  <button type="submit" className="btn btn-primary" disabled={busy}>
                    Anlegen
                  </button>
                </div>
              </form>
            </div>
          </div>
        ) : null}
      </div>
    )
  }

  return (
    <div className="exercise-progression-panel">
      <div style={{ marginBottom: '12px', display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'center' }}>
        <button
          type="button"
          className="btn btn-secondary"
          style={{ fontSize: '12px' }}
          disabled={busy}
          onClick={() => setSelectedGraphId(null)}
        >
          ← Zur Übersicht
        </button>
        <h2 style={{ margin: 0, fontSize: '1.1rem', flex: '1 1 auto' }}>
          {selectedGraph?.name || `Graph #${selectedGraphId}`}
        </h2>
      </div>

      {anchorExerciseId != null && (
        <p style={{ fontSize: '13px', color: 'var(--text2)', marginBottom: '12px' }}>
          Kontext:{' '}
          <strong>{anchorTitle?.trim() || `Übung #${anchorExerciseId}`}</strong>
          {' · '}
          <Link to={`/exercises/${anchorExerciseId}`}>Ansehen</Link>
        </p>
      )}

      {selectedGraphId && anchorExerciseId != null && (
        <label style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '12px', fontSize: '13px' }}>
          <input
            type="checkbox"
            checked={filterAnchorOnly}
            onChange={(e) => setFilterAnchorOnly(e.target.checked)}
          />
          Technische Kantenliste: nur Kanten mit dieser Übung
        </label>
      )}

      <ProgressionGraphEditor
        key={selectedGraphId}
        graphId={selectedGraphId}
        embedded
        onSaved={handleEditorSaved}
      />

      <details className="card" style={{ marginBottom: '12px', marginTop: '12px' }}>
        <summary style={{ cursor: 'pointer', fontWeight: 600 }}>Graph-Einstellungen (Name, Sichtbarkeit)</summary>
        <div style={{ marginTop: '14px' }}>
          <div className="form-row">
            <label className="form-label">Name</label>
            <input className="form-input" value={metaName} onChange={(e) => setMetaName(e.target.value)} />
          </div>
          <div className="form-row">
            <label className="form-label">Beschreibung</label>
            <textarea
              className="form-input"
              rows={2}
              value={metaDescription}
              onChange={(e) => setMetaDescription(e.target.value)}
            />
          </div>
          <div className="form-row">
            <label className="form-label">{EXERCISE_VISIBILITY_FIELD_LABEL}</label>
            <select
              className="form-input"
              value={metaVisibility}
              onChange={(e) => setMetaVisibility(e.target.value)}
            >
              {filteredGraphVisOptions.map((o) => (
                <option key={o.value} value={o.value}>
                  {o.label}
                </option>
              ))}
            </select>
          </div>
          <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
            <button type="button" className="btn btn-secondary" disabled={busy} onClick={handleSaveMeta}>
              Metadaten speichern
            </button>
            <button type="button" className="btn" disabled={busy} onClick={() => handleDeleteGraph(selectedGraph)}>
              Graph löschen
            </button>
          </div>
        </div>
      </details>

      <SkillProfilePanel
        title="Fähigkeiten entlang des Pfads"
        hint="Alle Übungen als Knoten im Graph."
        profile={skillProfileData?.overall}
        loading={skillProfileLoading}
        error={skillProfileError}
        defaultExpanded={false}
        artifactType="progression_graph"
      />

      <details className="card" style={{ marginBottom: '12px' }}>
        <summary style={{ cursor: 'pointer', fontWeight: 600 }}>
          Technische Kantenliste ({filteredEdges.length}
          {edges.length !== filteredEdges.length ? ` von ${edges.length}` : ''})
        </summary>
        <div style={{ marginTop: '14px' }}>
          {filteredEdges.length === 0 ? (
            <p style={{ color: 'var(--text2)', margin: 0 }}>Keine Kanten.</p>
          ) : (
            <div style={{ overflowX: 'auto' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '13px' }}>
                <thead>
                  <tr style={{ textAlign: 'left', borderBottom: '1px solid var(--border)' }}>
                    <th style={{ padding: '8px 6px' }}>Von</th>
                    <th style={{ padding: '8px 6px' }} />
                    <th style={{ padding: '8px 6px' }}>Nach</th>
                    <th style={{ padding: '8px 6px' }}>Art</th>
                    <th style={{ padding: '8px 6px' }}>Notiz</th>
                    <th style={{ padding: '8px 6px' }} />
                  </tr>
                </thead>
                <tbody>
                  {filteredEdges.map((row) => (
                    <tr key={row.id} style={{ borderBottom: '1px solid var(--border)' }}>
                      <td style={{ padding: '8px 6px', verticalAlign: 'top' }}>
                        <Link to={`/exercises/${row.from_exercise_id}`}>
                          {row.from_exercise_title || `#${row.from_exercise_id}`}
                        </Link>
                      </td>
                      <td style={{ padding: '8px 6px', color: 'var(--text3)', verticalAlign: 'top' }}>
                        {row.edge_type === 'sibling' ? '·' : '→'}
                      </td>
                      <td style={{ padding: '8px 6px', verticalAlign: 'top' }}>
                        <Link to={`/exercises/${row.to_exercise_id}`}>
                          {row.to_exercise_title || `#${row.to_exercise_id}`}
                        </Link>
                      </td>
                      <td style={{ padding: '8px 6px', verticalAlign: 'top' }}>{edgeTypeLabel(row.edge_type)}</td>
                      <td style={{ padding: '8px 6px', verticalAlign: 'top', maxWidth: '280px' }}>
                        {editingEdgeNotes === row.id ? (
                          <>
                            <textarea
                              className="form-input"
                              rows={2}
                              value={notesDraft}
                              onChange={(e) => setNotesDraft(e.target.value)}
                            />
                            <button
                              type="button"
                              className="btn btn-primary"
                              style={{ marginTop: '6px', fontSize: '12px', padding: '4px 8px' }}
                              onClick={() => saveNotes(row.id)}
                            >
                              Speichern
                            </button>
                          </>
                        ) : (
                          <>
                            {row.notes || '—'}
                            <button
                              type="button"
                              className="btn"
                              style={{ marginLeft: '8px', fontSize: '12px', padding: '4px 8px' }}
                              onClick={() => startEditNotes(row)}
                            >
                              Bearbeiten
                            </button>
                          </>
                        )}
                      </td>
                      <td style={{ padding: '8px 6px', verticalAlign: 'top' }}>
                        <button
                          type="button"
                          className="btn"
                          style={{
                            fontSize: '12px',
                            padding: '4px 8px',
                            background: 'var(--danger)',
                            color: '#fff',
                            border: 'none',
                          }}
                          onClick={() => handleDeleteEdge(row.id)}
                        >
                          Löschen
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>
      </details>
    </div>
  )
}

export default forwardRef(ExerciseProgressionGraphPanel)
