"use client"

// Shared data hook + source picker for the /embed/eval/* pages.
//
// Per-source (two-segment) embed ids behave exactly as before: one
// fetch, no picker. Merged (single-segment) ids default to the MERGED
// all-sources data and expose a compact "Source" selector so a viewer —
// or an embedder, via ?source=<composite_slug> — can pin one source's
// instantiation of the benchmark instead. Selecting a source swaps the
// embed's data to that source's per-source summary without navigating.

import { useEffect, useMemo, useState } from "react"

import { fetchEvalSummary, fetchMergedBenchmarkSummary } from "@/lib/dashboard-data-client"
import { isMergedBenchmarkSummary, mergedSummaryToEvalSummary } from "@/lib/merged-adapter"
import { isMergedEvalId } from "@/lib/utils"
import type { BenchmarkEvalSummary, MergedBenchmarkSummary } from "@/lib/eval-processing"

export interface EmbedSourceOption {
  /** Composite slug — the ?source= value. */
  slug: string
  label: string
  /** Two-segment per-source evaluation_id to fetch when selected. */
  evaluationId: string
}

export function useEmbedEvalSummary(
  evalId: string,
  opts: { metricParam?: string | null; sourceParam?: string | null } = {},
): {
  summary: BenchmarkEvalSummary | null
  error: string | null
  /** Non-null only for merged ids with at least one linkable source. */
  sources: EmbedSourceOption[] | null
  /** "" = merged (default). */
  activeSource: string
  setActiveSource: (slug: string) => void
} {
  const isMerged = isMergedEvalId(evalId)
  const metricId = opts.metricParam?.trim() || undefined

  // `base` = the embed's default data: the adapted merged summary for
  // merged ids, or the plain per-source summary otherwise.
  const [base, setBase] = useState<BenchmarkEvalSummary | null>(null)
  const [mergedRaw, setMergedRaw] = useState<MergedBenchmarkSummary | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [activeSource, setActiveSource] = useState<string>(
    () => opts.sourceParam?.trim() ?? "",
  )
  const [sourceSummary, setSourceSummary] = useState<BenchmarkEvalSummary | null>(null)

  useEffect(() => {
    let cancelled = false
    if (!isMerged) {
      fetchEvalSummary(evalId)
        .then((s) => {
          if (cancelled) return
          setBase(s)
          setError(null)
        })
        .catch((err) => {
          if (!cancelled) setError(err instanceof Error ? err.message : String(err))
        })
      return () => {
        cancelled = true
      }
    }
    fetchMergedBenchmarkSummary(evalId, { metricId })
      .then((payload) => {
        if (cancelled) return
        if (isMergedBenchmarkSummary(payload)) {
          setMergedRaw(payload)
          setBase(mergedSummaryToEvalSummary(payload))
          setError(null)
        } else if (payload && !("error" in payload)) {
          // Pre-merged-view snapshot: the API answered with a plain summary.
          setBase(payload)
          setError(null)
        } else {
          setError("Evaluation not found")
        }
      })
      .catch((err) => {
        if (!cancelled) setError(err instanceof Error ? err.message : String(err))
      })
    return () => {
      cancelled = true
    }
  }, [evalId, isMerged, metricId])

  const sources: EmbedSourceOption[] | null = useMemo(() => {
    if (!mergedRaw) return null
    // Every source with a per-source page is pinnable — a pinned source
    // shows ITS OWN per-source data, so sources that only report other
    // metrics (reports_preferred=false, e.g. HELM Capabilities on gpqa)
    // belong in the list too. Slice-only sources have no top-level page
    // to pin, so they stay out.
    const options = mergedRaw.aggregate_sources
      .filter((s) => s.evaluation_id && !s.slice_only)
      .map((s) => ({
        slug: s.composite_slug,
        label: s.composite_display_name || s.composite_slug,
        evaluationId: s.evaluation_id!,
      }))
    return options.length > 0 ? options : null
  }, [mergedRaw])

  // Ignore a ?source= that names no linkable source (typo / stale link):
  // fall back to merged rather than an empty embed.
  const effectiveSource =
    activeSource && sources?.some((s) => s.slug === activeSource) ? activeSource : ""

  useEffect(() => {
    if (!effectiveSource || !sources) {
      setSourceSummary(null)
      return
    }
    const target = sources.find((s) => s.slug === effectiveSource)
    if (!target) return
    let cancelled = false
    setSourceSummary(null)
    fetchEvalSummary(target.evaluationId)
      .then((s) => {
        if (cancelled) return
        setSourceSummary(s)
        setError(null)
      })
      .catch((err) => {
        if (!cancelled) setError(err instanceof Error ? err.message : String(err))
      })
    return () => {
      cancelled = true
    }
  }, [effectiveSource, sources])

  // Clear any stale error when the viewer changes selection, so a failed
  // pinned-source fetch doesn't leave the embed stuck on the error state
  // after switching back to Merged (or to another source).
  const selectSource = (slug: string) => {
    setError(null)
    setActiveSource(slug)
  }

  return {
    summary: effectiveSource ? sourceSummary : base,
    error,
    sources,
    activeSource: effectiveSource,
    setActiveSource: selectSource,
  }
}

/** Compact merged-vs-source selector, styled like the embeds' Split dropdown. */
export function EmbedSourcePicker({
  sources,
  value,
  onChange,
}: {
  sources: EmbedSourceOption[] | null
  value: string
  onChange: (slug: string) => void
}) {
  if (!sources || sources.length === 0) return null
  return (
    <div className="mb-3 flex items-center gap-3">
      <span
        className="font-mono uppercase shrink-0"
        style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
      >
        Source
      </span>
      <select
        className="ec-select"
        value={value}
        onChange={(e) => onChange(e.target.value)}
      >
        <option value="">Merged (all sources)</option>
        {sources.map((s) => (
          <option key={s.slug} value={s.slug}>
            {s.label}
          </option>
        ))}
      </select>
    </div>
  )
}
