import { useCallback, useEffect, useState } from 'react'

import type { DependencyEdge, GiteaIssue, GiteaMilestone, LifecycleEvent } from '@commitea/core'

export type BacklogState =
  | { status: 'loading' }
  | { status: 'unconfigured' }
  | { status: 'error'; message: string }
  | {
      status: 'ready'
      issues: GiteaIssue[]
      milestones: GiteaMilestone[]
      deps: DependencyEdge[]
      timelines: Record<number, LifecycleEvent[]>
      /** true while showing the persisted snapshot (instant boot / offline). */
      stale: boolean
      /** ISO time the shown snapshot was reconciled, when stale. */
      savedAt?: string
    }

/**
 * Reconcile the managed repo through the main-process bridge, stale-while-
 * revalidate: on mount it shows the persisted snapshot instantly (marked stale),
 * then a fresh reconcile supersedes it. If gitea is unreachable, the fresh
 * reconcile falls back to the persisted snapshot (offline). `refetch` re-syncs
 * after a write. `unconfigured` means no token — the UI uses demo fixtures.
 */
export function useBacklog(): [BacklogState, () => void] {
  const [state, setState] = useState<BacklogState>({ status: 'loading' })
  const [nonce, setNonce] = useState(0)
  const refetch = useCallback(() => setNonce((n) => n + 1), [])

  useEffect(() => {
    let alive = true

    // instant boot from the persisted snapshot (only on first mount, not refetch)
    if (nonce === 0) {
      window.commitea.gitea
        .boot()
        .then((b) => {
          if (!alive || !('cached' in b) || !b.cached) return
          setState((prev) =>
            prev.status === 'ready' && !prev.stale
              ? prev // a fresh reconcile already won the race
              : {
                  status: 'ready',
                  issues: b.issues,
                  milestones: b.milestones,
                  deps: b.deps,
                  timelines: b.timelines,
                  stale: true,
                  savedAt: b.savedAt,
                },
          )
        })
        .catch(() => {})
    }

    window.commitea.gitea
      .reconcile()
      .then((r) => {
        if (!alive) return
        setState(
          r.configured
            ? {
                status: 'ready',
                issues: r.issues,
                milestones: r.milestones,
                deps: r.deps,
                timelines: r.timelines,
                stale: r.stale ?? false,
                savedAt: r.savedAt,
              }
            : { status: 'unconfigured' },
        )
      })
      .catch((e: unknown) => {
        if (alive) {
          // keep a shown boot snapshot rather than clobbering it with an error
          setState((prev) =>
            prev.status === 'ready' ? prev : { status: 'error', message: e instanceof Error ? e.message : String(e) },
          )
        }
      })
    return () => {
      alive = false
    }
  }, [nonce])

  return [state, refetch]
}
