import {
  CriterionRow,
  PlanRunListRow,
  ScoreCard,
  SectionCard,
  SectionHeading,
  StaleBadge,
  VerdictBadge,
  formatRelativeTime,
  planStatusCategory,
  safeHttpUrl,
  useDeckTooltip,
} from '@overdeck/deck-ui'
import { useQuery } from '@tanstack/react-query'
import { adapterIdForPanel, fetchCollectorState } from '../../lib/collector-client'
import { criterionRowPropsFor, scoreCardPropsFor, verdictChipsFor } from '../../lib/overview-mappers'
import type { Criterion, GolivePanelData, HarnessPlansPanelData } from '../../lib/panel-data'
import { planTableItemForRun, projectRunsForRepo } from '../plans/plan-groups'

export interface ProjectDetailContentProps {
  repo: string
}

interface SectionGroup {
  section: string
  criteria: Criterion[]
}

function groupBySection(criteria: Criterion[]): SectionGroup[] {
  const groups: SectionGroup[] = []
  const indexBySection = new Map<string, number>()
  for (const criterion of criteria) {
    const section = criterion.section ?? 'General'
    let index = indexBySection.get(section)
    if (index === undefined) {
      index = groups.length
      indexBySection.set(section, index)
      groups.push({ section, criteria: [] })
    }
    groups[index].criteria.push(criterion)
  }
  return groups
}

/** Freshness of the scoreboard's source of truth: the repo's last GOLIVE.md commit. */
function SourceUpdatedAt({ iso, polledTs }: { iso: string | null; polledTs: string | undefined }) {
  const polled = polledTs === undefined ? undefined : `collector polled ${formatRelativeTime(Date.parse(polledTs))}`
  const tooltip = useDeckTooltip(iso ?? 'GOLIVE.md has no commits', polled)
  return (
    <span {...tooltip} className="text-[11px] text-fg-muted">
      {iso === null ? 'GOLIVE.md uncommitted' : `GOLIVE.md updated ${formatRelativeTime(Date.parse(iso))}`}
    </span>
  )
}

export function ProjectDetailContent({ repo }: ProjectDetailContentProps) {
  const stateQuery = useQuery({ queryKey: ['collector-state'], queryFn: fetchCollectorState })
  const scoreboardPanel = stateQuery.data?.panels.find((panel) => panel.id === 'scoreboard')
  const data = scoreboardPanel?.data as GolivePanelData | undefined
  const plansPanel = stateQuery.data?.panels.find((panel) => panel.id === 'plans')
  const plansData = plansPanel?.data as HarnessPlansPanelData | undefined
  const status = stateQuery.data?.adapters.find((adapter) => adapter.id === adapterIdForPanel('scoreboard'))

  const score = data?.repos.find((r) => r.repo === repo)
  const projectRuns = projectRunsForRepo(plansData?.runs ?? [], repo)

  if (stateQuery.isLoading) return <div className="text-fg-muted">Loading project…</div>
  if (!score) return <div className="text-fg-muted">No GOLIVE data for {repo}.</div>

  const failing = [
    ...score.criteria.filter((c) => c.verdict === 'broken'),
    ...score.criteria.filter((c) => c.verdict === 'missing'),
  ]

  return (
    <div className="flex flex-col gap-3.5">
      <SectionCard
        title={score.title ?? score.repo}
        titleBadge={
          <span className="flex items-center gap-2">
            {status ? <StaleBadge status={status} /> : null}
            <SourceUpdatedAt iso={score.sourceUpdatedAt} polledTs={scoreboardPanel?.ts} />
          </span>
        }
      >
        <div className="grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(24rem,0.85fr)]">
          <div className="min-w-0">
            <ScoreCard {...scoreCardPropsFor(score)} />
            <div className="flex items-center gap-3">
              {verdictChipsFor(score).map((chip) => (
                <span key={chip.verdict} className="flex items-center gap-1 text-[12px] text-fg-muted">
                  <VerdictBadge verdict={chip.verdict} />
                  {chip.count}
                </span>
              ))}
            </div>
            {score.summary !== null ? <p className="text-[12px] text-fg-muted">{score.summary}</p> : null}
          </div>
          <div className="min-w-0">
            <SectionHeading
              title="Associated plans"
              subtitle={`· ${projectRuns.length} active`}
              action={{ label: 'View all', href: '/plans' }}
            />
            {projectRuns.length > 0 ? (
              <div className="flex max-h-64 flex-col gap-2 overflow-y-auto pr-1">
                {projectRuns.map((run) => {
                  const item = planTableItemForRun(run)
                  return (
                    <PlanRunListRow
                      key={item.runId}
                      title={item.title || item.slug}
                      status={item.status}
                      tasksCompleted={item.tasksCompleted}
                      tasksTotal={item.tasksTotal}
                      updatedAtMs={item.updatedAtMs ?? Number.NaN}
                      activeAgents={item.activeAgents}
                      selected={planStatusCategory(item.status, item.needsYou) === 'running'}
                      onSelect={() => { const target = safeHttpUrl(item.href); if (target) window.location.assign(target) }}
                      href={safeHttpUrl(item.href)}
                    />
                  )
                })}
              </div>
            ) : (
              <p className="text-[12px] text-fg-muted">
                {plansData ? 'No active plans associated with this project.' : 'Plan data unavailable.'}
              </p>
            )}
          </div>
        </div>
      </SectionCard>

      {failing.length > 0 ? (
        <SectionCard title="Currently failing">
          {failing.map((c) => (
            <CriterionRow key={c.id} {...criterionRowPropsFor(c)} />
          ))}
        </SectionCard>
      ) : null}

      {groupBySection(score.criteria).map((group) => (
        <SectionCard key={group.section} title={group.section}>
          {group.criteria.map((c) => (
            <CriterionRow key={c.id} {...criterionRowPropsFor(c)} />
          ))}
        </SectionCard>
      ))}
    </div>
  )
}
