import { useEffect, useMemo, useState } from 'react';
import { formatAgo } from '@/lib/format';
import { Bot, Check, ChevronDown } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api/client';
import type { Agent, AgentParseError, ToolCostStat } from '@/api/types';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';

interface Props {
  projectId: string;
  value: string | null;
  onChange: (agentId: string | null) => void | Promise<void>;
}

export function AgentPicker({ projectId, value, onChange }: Props) {
  const [agents, setAgents] = useState<Agent[] | null>(null);
  const [parseErrors, setParseErrors] = useState<AgentParseError[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [open, setOpen] = useState(false);
  // v1.13.10: per-tool cost rolling window. Fetched once on mount; would
  // refresh on remount or page reload. Acceptable for a decision aid — the
  // 100-call rolling mean doesn't shift fast.
  const [costStats, setCostStats] = useState<ToolCostStat[]>([]);

  // v1.8.1: per-agent parse errors are non-blocking. Silent if any agents
  // loaded successfully; a gray warning toast fires only when EVERY agent
  // in AGENTS.md failed to parse. Server logs a console.warn either way.
  useEffect(() => {
    let cancelled = false;
    setAgents(null);
    setParseErrors([]);
    setError(null);
    api.agents
      .list(projectId)
      .then((res) => {
        if (cancelled) return;
        setAgents(res.agents);
        setParseErrors(res.errors);
        if (res.errors.length > 0 && res.agents.length === 0) {
          toast.warning(
            `AGENTS.md: ${res.errors.length} agent${res.errors.length === 1 ? '' : 's'} failed to parse, none loaded`,
          );
        }
      })
      .catch((err) => {
        if (cancelled) return;
        setError(err instanceof Error ? err.message : 'failed to load agents');
      });
    return () => {
      cancelled = true;
    };
  }, [projectId]);

  // v1.13.10: cost stats are project-independent — the 100-call rolling
  // window is global across all chats. Fetch once per mount; tolerate failure
  // silently (cost line hides).
  useEffect(() => {
    let cancelled = false;
    api.tools
      .costStats()
      .then((r) => {
        if (!cancelled) setCostStats(r.stats);
      })
      .catch(() => {
        if (!cancelled) setCostStats([]);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  const costByTool = useMemo(
    () => Object.fromEntries(costStats.map((s) => [s.tool_name, s])),
    [costStats],
  );

  const selectedAgent = agents?.find((a) => a.id === value) ?? null;
  const triggerLabel = value === null
    ? 'No agent'
    : selectedAgent?.name ?? value;

  return (
    <DropdownMenu open={open} onOpenChange={setOpen}>
      <DropdownMenuTrigger asChild>
        <button
          type="button"
          className="inline-flex items-center gap-1.5 rounded-full border border-border px-2.5 py-1 text-xs text-muted-foreground motion-reduce:transition-none transition-colors hover:bg-muted hover:text-foreground active:scale-[0.97] max-md:min-h-[36px] max-md:min-w-[36px]"
          title={selectedAgent?.name ? `Agent: ${selectedAgent.name}` : 'No agent'}
          aria-label={`Agent: ${triggerLabel}`}
        >
          <Bot className="size-3.5 shrink-0" />
          {/* Mobile = icon only; desktop keeps the agent name + chevron. */}
          <span className="truncate max-w-[160px] max-md:hidden">{triggerLabel}</span>
          <ChevronDown className="size-3 opacity-70 shrink-0 max-md:hidden" />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="start" className="max-h-80 overflow-y-auto w-96">
        {error && (
          <div className="px-2 py-1.5 text-xs text-destructive">{error}</div>
        )}
        {agents === null && !error && (
          <div className="px-2 py-1.5 text-xs text-muted-foreground">Loading…</div>
        )}
        {agents !== null && (
          <>
            <DropdownMenuItem
              onSelect={() => void onChange(null)}
              className="text-xs"
            >
              <Check className={`size-3 ${value === null ? 'opacity-100' : 'opacity-0'}`} />
              <span className="font-medium">No agent</span>
            </DropdownMenuItem>
            {agents.length > 0 && <DropdownMenuSeparator />}
            {agents.map((a) => {
              const cost = agentCost(a, costByTool);
              return (
                <DropdownMenuItem
                  key={a.id}
                  onSelect={() => void onChange(a.id)}
                  className="text-xs flex-col items-start gap-0.5"
                >
                  <div className="flex items-center gap-1.5">
                    <Check
                      className={`size-3 ${a.id === value ? 'opacity-100' : 'opacity-0'}`}
                    />
                    <span className="font-medium">{a.name}</span>
                  </div>
                  {a.description && (
                    <span className="text-muted-foreground pl-[18px] line-clamp-2 w-full">
                      {a.description}
                    </span>
                  )}
                  {cost.nWithData > 0 && (
                    <span className="text-muted-foreground/70 pl-[18px] truncate w-full">
                      ~{formatK(cost.prompt)} prompt / {cost.completion} completion · {cost.nWithData}/{cost.nTools} tools{cost.mostRecent ? ` · last call ${formatAgo(cost.mostRecent)}` : ''}
                    </span>
                  )}
                </DropdownMenuItem>
              );
            })}
            {parseErrors.length > 0 && (
              <div
                className="px-2 py-1.5 mt-1 text-xs text-amber-500 border-t border-border"
                title={parseErrors.map((e) => `${e.agent_name}: ${e.reason}`).join('\n')}
              >
                {parseErrors.length} agent{parseErrors.length === 1 ? '' : 's'} skipped
              </div>
            )}
          </>
        )}
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

// v1.13.10: sum the per-tool means across an agent's whitelisted tools.
// Sum-of-means, not mean-of-sums — we're combining independent rolling
// averages. nWithData reflects how many of the agent's tools have any
// history yet; the line hides entirely when zero so a fresh deploy doesn't
// render "0k / 0 / 0 tools".
function agentCost(
  agent: Agent,
  costByTool: Record<string, ToolCostStat>,
): {
  prompt: number;
  completion: number;
  nTools: number;
  nWithData: number;
  mostRecent: string | null;
} {
  let prompt = 0;
  let completion = 0;
  let nWithData = 0;
  let mostRecent: string | null = null;
  for (const t of agent.tools) {
    const s = costByTool[t];
    if (!s) continue;
    prompt += s.mean_prompt_tokens;
    completion += s.mean_completion_tokens;
    nWithData++;
    if (!mostRecent || s.updated_at > mostRecent) mostRecent = s.updated_at;
  }
  return { prompt, completion, nTools: agent.tools.length, nWithData, mostRecent };
}

function formatK(n: number): string {
  if (n < 1000) return String(n);
  if (n < 10_000) return `${(n / 1000).toFixed(1)}k`;
  return `${Math.round(n / 1000)}k`;
}

