import React, { useState, useEffect, useMemo, useCallback, useRef, lazy, Suspense } from 'react'
import { Link } from 'react-router-dom'
import api from '../../utils/api'
import { useAuth } from '../../context/AuthContext'
import { activeClubMemberships, getTenantClubDependencyKey } from '../../utils/activeClub'
import PageSectionNav from '../PageSectionNav'
import ExerciseListCard from './ExerciseListCard'
import ExerciseListFilterModal from './ExerciseListFilterModal'
import ExerciseListBulkModal from './ExerciseListBulkModal'
import ExerciseListSearchBar from './ExerciseListSearchBar'
import ExerciseListBulkToolbar from './ExerciseListBulkToolbar'
import { buildExerciseListFilterChips } from '../../utils/exerciseListFilterChips'
import { applyDashboardExerciseListUrl, buildExerciseListQueryBase } from '../../utils/exerciseListQuery'
import { useExerciseListCatalogsAndQuery } from '../../hooks/useExerciseListCatalogsAndQuery'
import {
  INITIAL_EXERCISE_LIST_FILTERS,
  mergeExerciseListPrefsFromApi,
  compactExerciseListPrefsPayload,
} from '../../constants/exerciseListFilters'

const ExerciseProgressionGraphPanel = lazy(() => import('../ExerciseProgressionGraphPanel'))

const BULK_MAX_IDS = 500
const EXERCISES_PAGE_TABS = [
  { id: 'list', label: 'Liste' },
  { id: 'progression', label: 'Progressionsgraphen' },
]

function ExercisesListPageRoot() {
  const { user, checkAuth } = useAuth()
  const isPlatformAdmin = user?.role === 'admin' || user?.role === 'superadmin'
  const isSuperadmin = user?.role === 'superadmin'
  const tenantClubDepKey = useMemo(() => getTenantClubDependencyKey(user), [user])

  const [mineOnly, setMineOnly] = useState(() => {
    try {
      const sp = new URLSearchParams(window.location.search)
      return sp.get('mine') === '1' || sp.get('created_by_me') === '1'
    } catch {
      return false
    }
  })

  const [searchInput, setSearchInput] = useState('')
  const [aiSearchInput, setAiSearchInput] = useState('')
  const [debouncedSearch, setDebouncedSearch] = useState('')
  const [debouncedAiSearch, setDebouncedAiSearch] = useState('')
  const [filters, setFilters] = useState(() => ({ ...INITIAL_EXERCISE_LIST_FILTERS }))
  const [filterModalOpen, setFilterModalOpen] = useState(false)
  const [savingExercisePrefs, setSavingExercisePrefs] = useState(false)
  const [pageTab, setPageTab] = useState('list')
  const prefsAppliedRef = useRef(false)

  const [selectedIds, setSelectedIds] = useState(() => new Set())
  const [bulkModalOpen, setBulkModalOpen] = useState(false)
  const [bulkVisibility, setBulkVisibility] = useState('')
  const [bulkStatus, setBulkStatus] = useState('')
  const [bulkClubSelect, setBulkClubSelect] = useState('')
  const [bulkClubManual, setBulkClubManual] = useState('')
  const [bulkSubmitting, setBulkSubmitting] = useState(false)
  const [bulkPatchFocusAreas, setBulkPatchFocusAreas] = useState(false)
  const [bulkFocusAreaIds, setBulkFocusAreaIds] = useState([])
  const [bulkPatchStyleDirections, setBulkPatchStyleDirections] = useState(false)
  const [bulkStyleDirectionIds, setBulkStyleDirectionIds] = useState([])
  const [bulkPatchTrainingTypes, setBulkPatchTrainingTypes] = useState(false)
  const [bulkTrainingTypeIds, setBulkTrainingTypeIds] = useState([])
  const [bulkPatchTargetGroups, setBulkPatchTargetGroups] = useState(false)
  const [bulkTargetGroupIds, setBulkTargetGroupIds] = useState([])

  useEffect(() => {
    if (!user?.id) return
    if (prefsAppliedRef.current) return
    const merged = mergeExerciseListPrefsFromApi(user.exercise_list_prefs)
    setFilters(applyDashboardExerciseListUrl(merged))
    try {
      const sp = new URLSearchParams(window.location.search)
      if (sp.get('mine') === '1' || sp.get('created_by_me') === '1') setMineOnly(true)
    } catch {
      /* ignore */
    }
    prefsAppliedRef.current = true
  }, [user?.id, user?.exercise_list_prefs])

  useEffect(() => {
    if (!user?.id) prefsAppliedRef.current = false
  }, [user?.id])

  useEffect(() => {
    const t = setTimeout(() => setDebouncedSearch(searchInput.trim()), 400)
    return () => clearTimeout(t)
  }, [searchInput])

  useEffect(() => {
    const t = setTimeout(() => setDebouncedAiSearch(aiSearchInput.trim()), 400)
    return () => clearTimeout(t)
  }, [aiSearchInput])

  useEffect(() => {
    if (!filterModalOpen) return
    const onKey = (e) => {
      if (e.key === 'Escape') setFilterModalOpen(false)
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [filterModalOpen])

  const queryBase = useMemo(
    () => buildExerciseListQueryBase(filters, debouncedSearch, debouncedAiSearch, mineOnly),
    [filters, debouncedSearch, debouncedAiSearch, mineOnly]
  )

  const {
    catalogs,
    catalogsReady,
    exercises,
    setExercises,
    listFetching,
    loadingMore,
    hasMore,
    loadMore,
  } = useExerciseListCatalogsAndQuery({ queryBase, pageTab, tenantClubDepKey })

  useEffect(() => {
    setSelectedIds(new Set())
  }, [queryBase])

  const focusOptions = useMemo(
    () =>
      catalogs.focusAreas.map((fa) => ({
        id: fa.id,
        label: `${fa.icon || ''} ${fa.name || ''}`.trim(),
      })),
    [catalogs.focusAreas]
  )
  const styleOptions = useMemo(
    () => catalogs.styleDirections.map((s) => ({ id: s.id, label: s.name || String(s.id) })),
    [catalogs.styleDirections]
  )
  const trainingTypeOptions = useMemo(
    () => catalogs.trainingTypes.map((t) => ({ id: t.id, label: t.name || String(t.id) })),
    [catalogs.trainingTypes]
  )
  const targetGroupOptions = useMemo(
    () => catalogs.targetGroups.map((g) => ({ id: g.id, label: g.name || String(g.id) })),
    [catalogs.targetGroups]
  )
  const skillOptions = useMemo(
    () => catalogs.skills.map((s) => ({ id: s.id, label: s.name || String(s.id) })),
    [catalogs.skills]
  )
  const visibilityOptions = useMemo(
    () => [
      { id: 'private', label: 'Privat' },
      { id: 'club', label: 'Verein' },
      { id: 'official', label: 'Offiziell' },
    ],
    []
  )
  const statusOptions = useMemo(
    () => [
      { id: 'draft', label: 'Entwurf' },
      { id: 'in_review', label: 'In Prüfung' },
      { id: 'approved', label: 'Freigegeben' },
      { id: 'archived', label: 'Archiviert' },
    ],
    []
  )

  const filterChips = useMemo(
    () =>
      buildExerciseListFilterChips({
        mineOnly,
        setMineOnly,
        filters,
        setFilters,
        focusOptions,
        styleOptions,
        trainingTypeOptions,
        targetGroupOptions,
        skillOptions,
        visibilityOptions,
        statusOptions,
      }),
    [
      mineOnly,
      filters,
      focusOptions,
      styleOptions,
      trainingTypeOptions,
      targetGroupOptions,
      skillOptions,
      visibilityOptions,
      statusOptions,
    ]
  )

  /** Für Browser-/datalist-Vorschläge (aktuelle Treffer-Titel, begrenzt) */
  const searchTitleSuggestions = useMemo(() => {
    const titles = exercises.map((e) => (e.title || '').trim()).filter(Boolean)
    return [...new Set(titles)].slice(0, 80)
  }, [exercises])

  const clubNameById = useMemo(() => {
    const m = {}
    for (const c of activeClubMemberships(user?.clubs)) {
      if (c?.id != null) m[Number(c.id)] = c.name || `#${c.id}`
    }
    return m
  }, [user?.clubs])

  const effectiveClubId =
    user?.effective_club_id != null && user.effective_club_id !== ''
      ? Number(user.effective_club_id)
      : user?.active_club_id != null && user.active_club_id !== ''
        ? Number(user.active_club_id)
        : null

  const toggleSelect = useCallback((id) => {
    setSelectedIds((prev) => {
      const n = new Set(prev)
      const nid = Number(id)
      if (Number.isNaN(nid)) return prev
      if (n.has(nid)) n.delete(nid)
      else n.add(nid)
      return n
    })
  }, [])

  const clearSelection = useCallback(() => setSelectedIds(new Set()), [])

  const toggleSelectAllPage = useCallback(() => {
    setSelectedIds((prev) => {
      const n = new Set(prev)
      const allSel =
        exercises.length > 0 && exercises.every((e) => n.has(Number(e.id)))
      if (allSel) {
        exercises.forEach((e) => n.delete(Number(e.id)))
      } else {
        exercises.forEach((e) => n.add(Number(e.id)))
      }
      return n
    })
  }, [exercises])

  const allOnPageSelected = useMemo(
    () => exercises.length > 0 && exercises.every((e) => selectedIds.has(Number(e.id))),
    [exercises, selectedIds]
  )

  const bulkVisibilityOptions = useMemo(() => {
    const base = [
      { id: '', label: '— nicht ändern —' },
      { id: 'private', label: 'Privat' },
      { id: 'club', label: 'Verein' },
    ]
    if (isSuperadmin) base.push({ id: 'official', label: 'Offiziell (global)' })
    return base
  }, [isSuperadmin])

  const handleDelete = async (exercise) => {
    if (!confirm(`Übung "${exercise.title}" wirklich löschen?`)) return
    try {
      await api.deleteExercise(exercise.id)
      setExercises((prev) => prev.filter((e) => e.id !== exercise.id))
    } catch (err) {
      alert('Fehler beim Löschen: ' + err.message)
    }
  }

  const resetAllFilters = useCallback(() => {
    setMineOnly(false)
    setFilters({ ...INITIAL_EXERCISE_LIST_FILTERS })
  }, [])

  const handleSaveExerciseFilterPrefs = useCallback(async () => {
    const uid = user?.id
    if (!uid) {
      alert('Nicht angemeldet.')
      return
    }
    setSavingExercisePrefs(true)
    try {
      const payload = compactExerciseListPrefsPayload(filters)
      await api.updateProfile(uid, { exercise_list_prefs: payload })
      await checkAuth()
      alert('Standardfilter für die Übungsliste gespeichert.')
    } catch (e) {
      alert('Speichern fehlgeschlagen: ' + (e.message || String(e)))
    } finally {
      setSavingExercisePrefs(false)
    }
  }, [user?.id, filters, checkAuth])

  const openBulkModal = () => {
    setBulkVisibility('')
    setBulkStatus('')
    setBulkClubSelect('')
    setBulkClubManual('')
    setBulkPatchFocusAreas(false)
    setBulkFocusAreaIds([])
    setBulkPatchStyleDirections(false)
    setBulkStyleDirectionIds([])
    setBulkPatchTrainingTypes(false)
    setBulkTrainingTypeIds([])
    setBulkPatchTargetGroups(false)
    setBulkTargetGroupIds([])
    setBulkModalOpen(true)
  }

  const handleBulkSubmit = async () => {
    const anyRelationPatch =
      bulkPatchFocusAreas ||
      bulkPatchStyleDirections ||
      bulkPatchTrainingTypes ||
      bulkPatchTargetGroups
    if (!bulkVisibility && !bulkStatus && !anyRelationPatch) {
      alert(
        'Bitte mindestens eine Änderung wählen (Sichtbarkeit, Status oder eine der Zuordnungen mit gesetztem Häkchen „ersetzen“).'
      )
      return
    }
    const ids = Array.from(selectedIds).filter((x) => Number.isFinite(x) && x > 0)
    if (ids.length === 0) {
      alert('Keine Übungen ausgewählt.')
      return
    }
    if (ids.length > BULK_MAX_IDS) {
      alert(`Maximal ${BULK_MAX_IDS} Übungen pro Vorgang. Bitte Auswahl oder mehrere Durchläufe verwenden.`)
      return
    }
    const payload = { exercise_ids: ids }
    if (bulkVisibility) payload.visibility = bulkVisibility
    if (bulkStatus) payload.status = bulkStatus
    if (bulkPatchFocusAreas) {
      payload.focus_area_ids = bulkFocusAreaIds.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
    }
    if (bulkPatchStyleDirections) {
      payload.style_direction_ids = bulkStyleDirectionIds.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
    }
    if (bulkPatchTrainingTypes) {
      payload.training_type_ids = bulkTrainingTypeIds.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
    }
    if (bulkPatchTargetGroups) {
      payload.target_group_ids = bulkTargetGroupIds.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
    }
    if (bulkVisibility === 'club') {
      const manual = String(bulkClubManual || '').trim()
      if (manual && /^\d+$/.test(manual)) payload.club_id = Number(manual)
      else if (bulkClubSelect && /^\d+$/.test(String(bulkClubSelect))) {
        payload.club_id = Number(bulkClubSelect)
      }
    }
    setBulkSubmitting(true)
    try {
      const res = await api.bulkPatchExercisesMetadata(payload)
      const updatedSet = new Set((res.updated || []).map((x) => Number(x)))
      let resolvedClubId = null
      if (bulkVisibility === 'club') {
        if (payload.club_id != null) resolvedClubId = payload.club_id
        else if (effectiveClubId != null && !Number.isNaN(effectiveClubId)) resolvedClubId = effectiveClubId
      }
      const clubLabel =
        resolvedClubId != null ? clubNameById[resolvedClubId] || `Verein #${resolvedClubId}` : null

      let nextPrimaryFocusName = null
      if (bulkPatchFocusAreas) {
        const faNums = bulkFocusAreaIds.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
        if (faNums.length > 0) {
          const opt = focusOptions.find((o) => Number(o.id) === Number(faNums[0]))
          nextPrimaryFocusName = String(opt?.label ?? '').trim() || String(faNums[0])
        }
      }

      setExercises((prev) =>
        prev.map((e) => {
          if (!updatedSet.has(Number(e.id))) return e
          const next = { ...e }
          if (bulkVisibility) {
            next.visibility = bulkVisibility
            next.club_id = bulkVisibility === 'club' ? resolvedClubId : null
            next.club_name = bulkVisibility === 'club' ? clubLabel : null
          }
          if (bulkStatus) next.status = bulkStatus
          if (bulkPatchFocusAreas) {
            if (nextPrimaryFocusName == null) delete next.focus_area
            else next.focus_area = nextPrimaryFocusName
          }
          return next
        })
      )

      let msg = `${res.updated_count ?? updatedSet.size} Übung(en) aktualisiert.`
      if (res.failed_count) msg += `\n${res.failed_count} nicht geändert (siehe Details).`
      if (Array.isArray(res.failed) && res.failed.length) {
        msg +=
          '\n\n' +
          res.failed
            .slice(0, 12)
            .map((f) => `#${f.id}: ${f.detail}`)
            .join('\n')
        if (res.failed.length > 12) msg += '\n…'
      }
      alert(msg)
      setBulkModalOpen(false)
      clearSelection()
    } catch (err) {
      alert('Massenänderung fehlgeschlagen: ' + (err.message || String(err)))
    } finally {
      setBulkSubmitting(false)
    }
  }

  if (!catalogsReady && pageTab === 'list') {
    return (
      <div className="app-page">
        <div className="empty-state" style={{ padding: '2.5rem 1rem' }}>
          <div className="spinner" />
          <p className="muted" style={{ marginTop: '12px' }}>
            Lade Kataloge…
          </p>
        </div>
      </div>
    )
  }

  return (
    <div className="app-page">
      <div className="exercises-page__header">
        <h1 className="page-title exercises-page__title">Übungen</h1>
        {pageTab === 'list' ? (
          <Link to="/exercises/new" className="btn btn-primary">
            + Neu
          </Link>
        ) : (
          <span aria-hidden="true" />
        )}
      </div>

      <PageSectionNav
        ariaLabel="Übungen Bereiche"
        value={pageTab}
        onChange={setPageTab}
        items={EXERCISES_PAGE_TABS}
        className="exercises-page-toolbar-tabs"
      />

      {pageTab === 'progression' ? (
        <Suspense
          fallback={
            <div className="card empty-state" style={{ padding: '2rem 1rem' }}>
              <div className="spinner" />
              <p className="muted" style={{ marginTop: '12px' }}>
                Lade Progressionsgraphen…
              </p>
            </div>
          }
        >
          <ExerciseProgressionGraphPanel />
        </Suspense>
      ) : (
        <>
      <ExerciseListSearchBar
        searchTitleSuggestions={searchTitleSuggestions}
        searchInput={searchInput}
        onSearchInputChange={setSearchInput}
        aiSearchInput={aiSearchInput}
        onAiSearchInputChange={setAiSearchInput}
        mineOnly={mineOnly}
        onToggleMineOnly={() => setMineOnly((v) => !v)}
        onOpenFilter={() => setFilterModalOpen(true)}
        filterChips={filterChips}
        onResetAllFilters={resetAllFilters}
        exerciseCount={exercises.length}
        allOnPageSelected={allOnPageSelected}
        onToggleSelectAllPage={toggleSelectAllPage}
      />

      <ExerciseListBulkToolbar
        selectedCount={selectedIds.size}
        bulkMaxIds={BULK_MAX_IDS}
        onClearSelection={clearSelection}
        onOpenBulkModal={openBulkModal}
      />

      <ExerciseListFilterModal
        open={filterModalOpen}
        onClose={() => setFilterModalOpen(false)}
        filters={filters}
        setFilters={setFilters}
        focusOptions={focusOptions}
        styleOptions={styleOptions}
        trainingTypeOptions={trainingTypeOptions}
        targetGroupOptions={targetGroupOptions}
        skillOptions={skillOptions}
        visibilityOptions={visibilityOptions}
        statusOptions={statusOptions}
        savingExercisePrefs={savingExercisePrefs}
        onSaveStandard={handleSaveExerciseFilterPrefs}
        onResetAll={resetAllFilters}
      />

      <ExerciseListBulkModal
        open={bulkModalOpen}
        onClose={() => setBulkModalOpen(false)}
        onSubmit={handleBulkSubmit}
        bulkSubmitting={bulkSubmitting}
        selectedCount={selectedIds.size}
        bulkMaxIds={BULK_MAX_IDS}
        user={user}
        isPlatformAdmin={isPlatformAdmin}
        statusOptions={statusOptions}
        bulkVisibilityOptions={bulkVisibilityOptions}
        focusOptions={focusOptions}
        styleOptions={styleOptions}
        trainingTypeOptions={trainingTypeOptions}
        targetGroupOptions={targetGroupOptions}
        bulkVisibility={bulkVisibility}
        setBulkVisibility={setBulkVisibility}
        bulkStatus={bulkStatus}
        setBulkStatus={setBulkStatus}
        bulkClubSelect={bulkClubSelect}
        setBulkClubSelect={setBulkClubSelect}
        bulkClubManual={bulkClubManual}
        setBulkClubManual={setBulkClubManual}
        bulkPatchFocusAreas={bulkPatchFocusAreas}
        setBulkPatchFocusAreas={setBulkPatchFocusAreas}
        bulkFocusAreaIds={bulkFocusAreaIds}
        setBulkFocusAreaIds={setBulkFocusAreaIds}
        bulkPatchStyleDirections={bulkPatchStyleDirections}
        setBulkPatchStyleDirections={setBulkPatchStyleDirections}
        bulkStyleDirectionIds={bulkStyleDirectionIds}
        setBulkStyleDirectionIds={setBulkStyleDirectionIds}
        bulkPatchTrainingTypes={bulkPatchTrainingTypes}
        setBulkPatchTrainingTypes={setBulkPatchTrainingTypes}
        bulkTrainingTypeIds={bulkTrainingTypeIds}
        setBulkTrainingTypeIds={setBulkTrainingTypeIds}
        bulkPatchTargetGroups={bulkPatchTargetGroups}
        setBulkPatchTargetGroups={setBulkPatchTargetGroups}
        bulkTargetGroupIds={bulkTargetGroupIds}
        setBulkTargetGroupIds={setBulkTargetGroupIds}
      />

      {listFetching && exercises.length === 0 ? (
        <div className="card empty-state" style={{ padding: '2rem 1rem' }}>
          <div className="spinner" />
          <p className="muted" style={{ marginTop: '12px' }}>
            Lade Übungen…
          </p>
        </div>
      ) : exercises.length === 0 ? (
        <div className="card">
          <p className="exercises-empty-text">Keine Übungen gefunden.</p>
        </div>
      ) : (
        <>
          {listFetching ? (
            <p className="exercises-meta-line exercises-meta-line--muted">Aktualisiere Treffer…</p>
          ) : null}
          <p className="exercises-meta-line">
            {exercises.length} angezeigt
            {hasMore ? ' · es gibt weitere Einträge' : ''}
          </p>
          <div className="exercises-list-grid" data-testid="exercises-list-grid">
            {exercises.map((exercise) => (
              <ExerciseListCard
                key={exercise.id}
                exercise={exercise}
                user={user}
                selectedIds={selectedIds}
                toggleSelect={toggleSelect}
                onDelete={handleDelete}
              />
            ))}
          </div>
          {hasMore && (
            <div className="exercises-load-more">
              <button type="button" className="btn btn-secondary" disabled={loadingMore} onClick={loadMore}>
                {loadingMore ? 'Laden…' : 'Mehr laden'}
              </button>
            </div>
          )}
        </>
      )}
    </>
      )}
    </div>
  )
}

export default ExercisesListPageRoot
