import { useEffect, useMemo, useState } from 'react'
import type { StoryGroup } from '../types/jira'
import type { FunctionalGapBadge } from '../lib/dashboardConfig'
import { fetchAllIssueKeysInSprint } from '../api/jiraClient'
import { useStatusBuckets } from '../context/StatusBucketContext'
import type { JiraSprintSnapshot } from '../lib/sprintExtract'
import {
  collectSprintOptions,
  filterGroupsBySprint,
  filterGroupsBySprintIssueKeys,
  sprintOptionsFromBoardAndGroups,
  sprintOptionsFromBoardOnly,
} from '../lib/sprintExtract'
import { subtaskDoneRatioPercent } from '../lib/storyMetrics'
import { StoryCard } from './StoryCard'

type Props = {
  groups: StoryGroup[]
  sprintFieldId: string | null
  /** Sprints actifs/futurs depuis l’API Agile du board (sans élargir le périmètre JQL). */
  boardSprintsFromApi?: JiraSprintSnapshot[]
  onOpenSettings: () => void
  gapBadges?: FunctionalGapBadge[]
}

export function SprintView({
  groups,
  sprintFieldId,
  boardSprintsFromApi = [],
  onOpenSettings,
  gapBadges,
}: Props) {
  const cfg = useStatusBuckets()
  const [focusId, setFocusId] = useState<number | 'all'>('all')
  const [sprintIssueKeys, setSprintIssueKeys] = useState<Set<string>>(new Set())
  const [sprintIssuesLoading, setSprintIssuesLoading] = useState(false)

  const options = useMemo(() => {
    if (boardSprintsFromApi.length > 0) {
      if (sprintFieldId) {
        const fromBoard = sprintOptionsFromBoardAndGroups(
          boardSprintsFromApi,
          groups,
          sprintFieldId,
        )
        if (fromBoard.length > 0) return fromBoard
      } else {
        return sprintOptionsFromBoardOnly(boardSprintsFromApi)
      }
    }
    if (sprintFieldId) return collectSprintOptions(groups, sprintFieldId)
    return []
  }, [boardSprintsFromApi, groups, sprintFieldId])

  useEffect(() => {
    if (sprintFieldId || focusId === 'all') {
      setSprintIssueKeys(new Set())
      setSprintIssuesLoading(false)
      return
    }
    const sprintId = focusId as number
    const ac = new AbortController()
    setSprintIssuesLoading(true)
    setSprintIssueKeys(new Set())
    void fetchAllIssueKeysInSprint(sprintId, ac.signal)
      .then((set) => {
        if (!ac.signal.aborted) setSprintIssueKeys(set)
      })
      .catch(() => {
        if (!ac.signal.aborted) setSprintIssueKeys(new Set())
      })
      .finally(() => {
        if (!ac.signal.aborted) setSprintIssuesLoading(false)
      })
    return () => ac.abort()
  }, [focusId, sprintFieldId])

  const filtered = useMemo(() => {
    if (focusId === 'all') return groups
    if (sprintFieldId) return filterGroupsBySprint(groups, focusId, sprintFieldId)
    if (sprintIssuesLoading) return []
    return filterGroupsBySprintIssueKeys(groups, sprintIssueKeys)
  }, [groups, focusId, sprintFieldId, sprintIssueKeys, sprintIssuesLoading])

  const stats = useMemo(() => {
    let subs = 0
    let sumPct = 0
    let nWithSubs = 0
    for (const g of filtered) {
      subs += g.subtasks.length
      if (g.subtasks.length > 0) {
        sumPct += subtaskDoneRatioPercent(g.subtasks, cfg)
        nWithSubs += 1
      }
    }
    const avgPct = nWithSubs > 0 ? Math.round(sumPct / nWithSubs) : 0
    return { stories: filtered.length, subtasks: subs, avgPct }
  }, [filtered, cfg])

  /** Aucune liste possible : ni board Agile, ni champ Sprint sur les tickets. */
  const mustConfigureSprintField = options.length === 0 && !sprintFieldId && boardSprintsFromApi.length === 0

  if (mustConfigureSprintField) {
    return (
      <section className="mb-10 rounded-2xl border border-amber-500/25 bg-amber-500/5 px-5 py-8 text-center backdrop-blur-xl sm:px-8">
        <h2 className="text-sm font-semibold uppercase tracking-[0.18em] text-amber-200/90">
          Vue Sprint — configuration requise
        </h2>
        <p className="mx-auto mt-3 max-w-xl text-sm leading-relaxed text-amber-100/90">
          Aucun sprint actif/futur n’a été reçu du board Agile, et le champ Sprint n’est pas
          renseigné. Indiquez l’identifiant du champ personnalisé Sprint (souvent{' '}
          <code className="rounded bg-black/30 px-1 font-mono text-xs">customfield_10020</code>) dans
          les réglages ou via{' '}
          <code className="rounded bg-black/30 px-1 font-mono text-xs">VITE_JIRA_SPRINT_FIELD</code>,
          ou vérifiez le board (<code className="rounded bg-black/30 px-1 font-mono text-xs">VITE_JIRA_BOARD_ID</code>
          ) puis actualisez.
        </p>
        <button
          type="button"
          onClick={onOpenSettings}
          className="mt-5 rounded-lg border border-cyan-500/50 bg-cyan-500/15 px-4 py-2 text-sm font-medium text-cyan-100"
        >
          Ouvrir les réglages
        </button>
      </section>
    )
  }

  if (options.length === 0) {
    return (
      <section className="mb-10 rounded-2xl border border-white/[0.08] bg-slate-950/40 px-5 py-8 backdrop-blur-xl sm:px-8">
        <h2 className="text-sm font-semibold uppercase tracking-[0.18em] text-slate-400">
          Vue Sprint
        </h2>
        <p className="mt-3 text-sm text-slate-400">
          Aucun sprint actif ou futur sur le board, et aucun sprint détecté sur les tickets chargés.
        </p>
      </section>
    )
  }

  const filterModeAgile = !sprintFieldId && boardSprintsFromApi.length > 0

  return (
    <section className="mb-10 space-y-6">
      {filterModeAgile && (
        <div className="rounded-xl border border-sky-500/25 bg-sky-500/10 px-4 py-3 text-xs leading-relaxed text-sky-100/95">
          Filtre sprint via l’API Agile Jira (issues du sprint). Pour afficher les pastilles sprint
          sur chaque carte, renseignez aussi le champ Sprint (ID{' '}
          <code className="rounded bg-black/30 px-1 font-mono text-[11px]">customfield_…</code>) dans
          les réglages.
        </div>
      )}

      <div className="rounded-2xl border border-white/[0.08] bg-slate-950/40 px-4 py-4 backdrop-blur-xl sm:px-6">
        <div className="flex flex-wrap items-end justify-between gap-4">
          <div>
            <h2 className="text-sm font-semibold uppercase tracking-[0.18em] text-slate-400">
              Vue Sprint
            </h2>
            <p className="mt-1 max-w-2xl text-xs text-slate-500">
              {sprintFieldId ? (
                <>
                  Sprints actifs/futurs du board Jira Agile ; le nombre de stories compte le
                  périmètre chargé (épopée) avec le champ Sprint sur les tickets.
                </>
              ) : (
                <>
                  Sprints actifs/futurs du board (API Agile). Le filtre par sprint interroge les
                  issues du sprint côté Jira ; le périmètre affiché reste celui de l’épopée Golden
                  Carbon.
                </>
              )}
            </p>
          </div>
          <div className="flex min-w-[200px] flex-1 flex-col gap-1 sm:max-w-md">
            <label className="text-[10px] font-medium uppercase tracking-wide text-slate-500">
              Sprint ciblé
            </label>
            <select
              value={focusId === 'all' ? 'all' : String(focusId)}
              onChange={(e) => {
                const v = e.target.value
                setFocusId(v === 'all' ? 'all' : Number(v))
              }}
              className="rounded-lg border border-white/10 bg-black/40 px-3 py-2 text-sm text-slate-200 outline-none ring-cyan-500/20 focus:ring-2"
            >
              <option value="all">Tous les sprints ({groups.length} stories)</option>
              {options.map((s) => (
                <option key={s.id} value={String(s.id)}>
                  {s.name}
                  {s.state ? ` (${s.state})` : ''}
                  {sprintFieldId ? ` — ${s.storyCount} stories` : ''}
                </option>
              ))}
            </select>
          </div>
        </div>

        <div className="mt-4 flex flex-wrap gap-4 border-t border-white/[0.06] pt-4 text-sm text-slate-400">
          <span>
            Stories :{' '}
            <span className="font-mono font-semibold text-slate-200">{stats.stories}</span>
          </span>
          <span>
            Sous-tâches :{' '}
            <span className="font-mono font-semibold text-slate-200">{stats.subtasks}</span>
          </span>
          <span title="Moyenne des % sous-tâches terminées sur les stories qui ont des sous-tâches">
            Avancement moy. :{' '}
            <span className="font-mono font-semibold text-emerald-300">{stats.avgPct}%</span>
          </span>
        </div>
      </div>

      {sprintIssuesLoading && focusId !== 'all' && !sprintFieldId ? (
        <p className="rounded-2xl border border-white/10 bg-slate-950/35 px-6 py-8 text-center text-sm text-slate-400">
          Chargement des tickets du sprint…
        </p>
      ) : filtered.length === 0 ? (
        <p className="rounded-2xl border border-white/10 bg-slate-950/35 px-6 py-8 text-center text-sm text-slate-400">
          Aucune story du périmètre dans ce sprint (filtre « Ma vue » inclus), ou erreur lors du
          chargement des issues du sprint.
        </p>
      ) : (
        <div className="grid grid-cols-1 gap-5 lg:grid-cols-2">
          {filtered.map((g) => (
            <StoryCard
              key={g.story.key}
              group={g}
              sprintFieldId={sprintFieldId}
              gapBadges={gapBadges}
            />
          ))}
        </div>
      )}
    </section>
  )
}
