import {
  AbandonedPlansTable,
  DeckTooltipLayer,
  SectionCard,
  SectionHeading,
  UndoToast,
  type AbandonedPlanItem,
  type UndoToastHandle,
} from '@overdeck/deck-ui'
import { useQueryClient } from '@tanstack/react-query'
import { useRef, useState } from 'react'
import { postCollectorAction } from '../../lib/action-client'
import { useCollectorState } from '../../lib/collector-queries'
import type { HarnessPlanRun, HarnessPlansPanelData } from '../../lib/panel-data'
import { CollectorPageApp } from '../shared/CollectorPageApp'
import { CollectorQueryBoundary } from '../shared/CollectorQueryBoundary'
import { projectLabelForRun } from './plan-groups'

export function abandonedPlanItemForRun(run: HarnessPlanRun): AbandonedPlanItem | null {
  if (!run.abandonedAt) return null
  const abandonedAtMs = Date.parse(run.abandonedAt)
  if (!Number.isFinite(abandonedAtMs)) return null
  return {
    runId: run.runId,
    slug: run.registry?.slug || run.runId,
    title: run.title,
    projectLabel: projectLabelForRun(run),
    failLabel: run.failClass || run.degradedReason || null,
    abandonedAtMs,
    href: `/plans/${encodeURIComponent(run.runId)}`,
  }
}

function AbandonedContentInner() {
  const stateQuery = useCollectorState()
  return (
    <CollectorQueryBoundary query={stateQuery}>
      {(state) => <AbandonedContentBody state={state} />}
    </CollectorQueryBoundary>
  )
}

function AbandonedContentBody({ state }: { state: import('../../lib/collector-types').StateResponse }) {
  const queryClient = useQueryClient()
  const [restoringRunIds, setRestoringRunIds] = useState<Set<string>>(() => new Set())
  const toastRef = useRef<UndoToastHandle>(null)

  const plansPanel = state.panels.find((panel) => panel.id === 'plans')
  const runs = (plansPanel?.data as HarnessPlansPanelData | undefined)?.runs ?? []
  const abandonedRuns = runs.filter((run) => run.abandoned)
  const timestampGaps = abandonedRuns.filter((run) => abandonedPlanItemForRun(run) === null).length
  const items = abandonedRuns
    .map(abandonedPlanItemForRun)
    .filter((item): item is AbandonedPlanItem => item !== null)
    .filter((item) => !restoringRunIds.has(item.runId))

  const restore = (item: AbandonedPlanItem) => {
    setRestoringRunIds((current) => new Set(current).add(item.runId))
    void postCollectorAction('restore', {
      args: { runId: item.runId },
      requestedBy: 'overdeck-web',
    }).then(
      async () => {
        toastRef.current?.toast(`Restored ${item.title || item.slug}.`)
        await queryClient.invalidateQueries({ queryKey: ['collector-state'] })
      },
      (error: unknown) => {
        setRestoringRunIds((current) => {
          const next = new Set(current)
          next.delete(item.runId)
          return next
        })
        toastRef.current?.toast(error instanceof Error ? error.message : String(error))
      },
    ).catch((error: unknown) => {
      toastRef.current?.toast(error instanceof Error ? error.message : String(error))
    })
  }

  return (
    <div className="flex min-w-0 flex-col gap-4">
      <a
        href="/plans"
        className="inline-flex min-h-11 w-fit items-center text-sm font-semibold text-fg-muted no-underline hover:text-fg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
      >
        ← Plans
      </a>
      <SectionHeading
        title="Abandoned plans"
        subtitle="· soft-removed runs remain restorable"
      />
      <SectionCard title="Plan history">
        {timestampGaps > 0 && (
          <p className="mb-3 text-xs text-warning">
            {timestampGaps} abandoned {timestampGaps === 1 ? 'plan is' : 'plans are'} missing a recorded abandoned time.
          </p>
        )}
        {items.length === 0 && timestampGaps > 0 ? (
          <p className="py-8 text-center text-sm text-fg-muted">
            Abandoned plan details are incomplete. Wait for the next collector snapshot.
          </p>
        ) : (
          <AbandonedPlansTable items={items} onRestore={restore} />
        )}
      </SectionCard>
      <UndoToast handleRef={toastRef} />
      <DeckTooltipLayer />
    </div>
  )
}

export function AbandonedContent() {
  return (
    <CollectorPageApp>
      <AbandonedContentInner />
    </CollectorPageApp>
  )
}
