import { useMemo } from "react";
import type { ReplaySession } from "../types";
import { formatReplaySourceLabel } from "../utils/format";
import {
  DataQualityIndicator,
  getSessionDataQualityNotes,
  getSessionMetricQuality,
} from "./DataQualityIndicator";
import { rollupProject } from "./dashboard-utils";

interface Props {
  session: ReplaySession;
}

export default function StatsPanel({ session }: Props) {
  const stats = useMemo(() => {
    const { scenes, meta } = session;

    const toolCounts = new Map<string, number>();
    let thinkingChars = 0;
    let responseChars = 0;
    let promptChars = 0;
    let editCount = 0;
    let subAgentCount = 0;
    let delegatedTools = 0;
    const filesModified = new Set<string>();

    for (const scene of scenes) {
      switch (scene.type) {
        case "user-prompt":
          promptChars += scene.content.length;
          break;
        case "thinking":
          thinkingChars += scene.content.length;
          break;
        case "text-response":
          responseChars += scene.content.length;
          break;
        case "tool-call": {
          toolCounts.set(scene.toolName, (toolCounts.get(scene.toolName) || 0) + 1);
          if (scene.diff) {
            editCount++;
            filesModified.add(scene.diff.filePath);
          }
          if (scene.subAgent) {
            subAgentCount++;
            delegatedTools += scene.subAgent.toolCalls;
            // Count file modifications from sub-agent scenes
            for (const saScene of scene.subAgent.scenes) {
              if (saScene.type === "tool-call" && saScene.diff) {
                editCount++;
                filesModified.add(saScene.diff.filePath);
              }
            }
          }
          break;
        }
      }
    }

    const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 6);

    return {
      totalScenes: scenes.length,
      userPrompts: meta.stats.userPrompts,
      toolCalls: meta.stats.toolCalls,
      thinkingChars,
      responseChars,
      promptChars,
      editCount,
      filesModified: filesModified.size,
      subAgentCount,
      delegatedTools,
      topTools,
      durationMs: meta.stats.durationMs,
      tokenUsage: meta.stats.tokenUsage,
      costEstimate: meta.stats.costEstimate,
      compactions: meta.compactions,
      peakContextTokens: (() => {
        if (!meta.stats.turnStats?.length) return undefined;
        const peak = Math.max(...meta.stats.turnStats.map((t) => t.contextTokens || 0));
        return peak > 0 ? peak : undefined;
      })(),
      medianTurnDurationMs: (() => {
        const durations = meta.stats.turnStats
          ?.map((t) => t.durationMs)
          .filter((d): d is number => d != null && d > 0);
        if (!durations?.length) return undefined;
        const sorted = [...durations].sort((a, b) => a - b);
        const mid = Math.floor(sorted.length / 2);
        return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
      })(),
    };
  }, [session]);

  const { meta } = session;
  const displayProject = rollupProject(meta.project);
  const isWorktree = displayProject !== meta.project;
  const dataQualityNotes = useMemo(() => getSessionDataQualityNotes(meta), [meta]);
  const metricQuality = useMemo(() => getSessionMetricQuality(meta), [meta]);

  return (
    <div className="p-4 space-y-6 ui-caption">
      {/* Session info */}
      <div>
        <div className="ui-section-title mb-2">Session</div>
        {meta.title && (
          <div className="text-terminal-text text-xs mb-0.5 truncate" title={meta.title}>
            {meta.title}
          </div>
        )}
        <div className="text-terminal-dim truncate" title={isWorktree ? meta.project : meta.cwd}>
          {displayProject}
        </div>
        <div className="text-terminal-dim mt-0.5 flex items-center gap-1.5 flex-wrap">
          {meta.model && <span className="text-terminal-dim">{meta.model}</span>}
          {meta.provider && <span>{meta.provider}</span>}
          {isWorktree && (
            <span
              className="ui-pill-compact bg-terminal-purple-subtle text-terminal-purple"
              title={`Agent worktree: ${meta.project}`}
            >
              worktree
            </span>
          )}
          {dataQualityNotes.length > 0 && (
            <DataQualityIndicator title={dataQualityNotes.join("\n")} />
          )}
        </div>
        {meta.gitBranch && (
          <div className="text-terminal-dim mt-0.5">
            <span className="text-terminal-purple truncate block" title={meta.gitBranch}>
              {meta.gitBranch}
            </span>
            {meta.gitBranches && meta.gitBranches.length > 1 && (
              <span className="text-[10px] text-terminal-dimmer">
                {meta.gitBranches.slice(0, -1).join(" → ")} → {meta.gitBranch}
              </span>
            )}
          </div>
        )}
        {(meta.entrypoint || meta.permissionMode || meta.memoryMode) && (
          <div className="text-terminal-dim mt-0.5 flex items-center gap-1.5 flex-wrap text-xs">
            {meta.entrypoint && (
              <span className="px-1 py-0.5 rounded bg-terminal-surface text-terminal-dim">
                {meta.entrypoint}
              </span>
            )}
            {meta.memoryMode && (
              <span className="px-1 py-0.5 rounded bg-terminal-surface text-terminal-dim">
                memory: {meta.memoryMode}
              </span>
            )}
            {meta.permissionMode === "bypassPermissions" && (
              <span className="px-1 py-0.5 rounded bg-terminal-orange/20 text-terminal-orange">
                dangerous
              </span>
            )}
          </div>
        )}
        {meta.generator?.version && (
          <div className="text-terminal-dim mt-0.5 truncate">
            replay:{" "}
            <span className="text-terminal-text">
              {meta.generator.name} v{meta.generator.version}
            </span>
          </div>
        )}
        {meta.generator?.generatedAt && (
          <div className="text-terminal-dim mt-0.5 truncate" title={meta.generator.generatedAt}>
            generated:{" "}
            <span className="text-terminal-text">
              {formatGeneratedAt(meta.generator.generatedAt)}
            </span>
          </div>
        )}
      </div>

      <div className="grid grid-cols-2 gap-2">
        <StatCard label="Turns" value={stats.userPrompts} color="text-terminal-green" />
        <StatCard label="Scenes" value={stats.totalScenes} color="text-terminal-text" />
        <StatCard label="Tool Calls" value={stats.toolCalls} color="text-terminal-orange" />
        <StatCard label="Files Modified" value={stats.filesModified} color="text-terminal-blue" />
      </div>

      {(stats.durationMs ||
        stats.costEstimate !== undefined ||
        metricQuality.duration ||
        metricQuality.tokens ||
        metricQuality.turnStats) && (
        <div className="text-terminal-dim space-y-0.5">
          {(stats.durationMs || metricQuality.duration) && (
            <div>
              Duration:{" "}
              <span className="text-terminal-text">
                {stats.durationMs ? formatDuration(stats.durationMs) : "unavailable"}
              </span>
              {metricQuality.duration && (
                <DataQualityIndicator title={metricQuality.duration} className="ml-1" />
              )}
            </div>
          )}
          {stats.costEstimate !== undefined && (
            <div>
              Cost:{" "}
              <span className="text-terminal-green">
                $
                {stats.costEstimate < 0.01
                  ? stats.costEstimate.toFixed(4)
                  : stats.costEstimate.toFixed(2)}
              </span>
              <span className="text-terminal-dimmer"> (estimate)</span>
              {metricQuality.tokens && (
                <DataQualityIndicator title={metricQuality.tokens} className="ml-1" />
              )}
            </div>
          )}
          {!stats.tokenUsage && metricQuality.tokens && (
            <div>
              Tokens: <span className="text-terminal-text">unavailable</span>
              <DataQualityIndicator title={metricQuality.tokens} className="ml-1" />
            </div>
          )}
          {!meta.stats.turnStats?.length && metricQuality.turnStats && (
            <div>
              Turn Stats: <span className="text-terminal-text">limited</span>
              <DataQualityIndicator title={metricQuality.turnStats} className="ml-1" />
            </div>
          )}
        </div>
      )}

      {stats.tokenUsage && (
        <div>
          <div className="ui-section-title mb-2 flex items-center gap-1.5">
            Tokens
            {metricQuality.tokens && <DataQualityIndicator title={metricQuality.tokens} />}
          </div>
          <div className="text-terminal-dim leading-relaxed space-y-0.5">
            <div>
              In: <span className="text-terminal-blue">{fmtNum(stats.tokenUsage.inputTokens)}</span>
              {" / "}
              Out:{" "}
              <span className="text-terminal-green">{fmtNum(stats.tokenUsage.outputTokens)}</span>
            </div>
            <div>
              Cache:{" "}
              <span className="text-terminal-purple">
                {fmtNum(stats.tokenUsage.cacheReadTokens)}
              </span>{" "}
              read
              {" / "}
              <span className="text-terminal-orange">
                {fmtNum(stats.tokenUsage.cacheCreationTokens)}
              </span>{" "}
              created
            </div>
          </div>
        </div>
      )}

      {/* Peak context */}
      {stats.peakContextTokens !== undefined && (
        <div className="text-terminal-dim">
          Peak context:{" "}
          <span className="text-terminal-cyan">{fmtNum(stats.peakContextTokens)}</span>
          <span className="text-terminal-dimmer"> tokens</span>
        </div>
      )}

      {/* Efficiency metrics */}
      {stats.medianTurnDurationMs != null && (
        <div className="text-terminal-dim">
          Median TTI:{" "}
          <span className="text-terminal-text">{formatDuration(stats.medianTurnDurationMs)}</span>
        </div>
      )}

      {/* Sub-agents summary */}
      {stats.subAgentCount > 0 && (
        <div className="text-terminal-dim">
          Sub-agents: <span className="text-terminal-text">{stats.subAgentCount}</span>
          {stats.delegatedTools > 0 && (
            <span className="text-terminal-dimmer"> ({stats.delegatedTools} tools delegated)</span>
          )}
        </div>
      )}

      {/* API Errors */}
      {meta.apiErrors && meta.apiErrors.length > 0 && (
        <div className="text-terminal-dim">
          API errors: <span className="text-terminal-red">{meta.apiErrors.length}</span>
          {(() => {
            const types = new Map<string, number>();
            for (const e of meta.apiErrors) {
              const key = e.errorType || `${e.statusCode}`;
              types.set(key, (types.get(key) || 0) + 1);
            }
            return (
              <span className="text-terminal-dimmer text-[10px]">
                {" "}
                (
                {[...types.entries()]
                  .sort((a, b) => b[1] - a[1])
                  .map(([t, c]) => `${t} x${c}`)
                  .join(", ")}
                )
              </span>
            );
          })()}
        </div>
      )}

      {/* Tracked Files */}
      {meta.trackedFiles && meta.trackedFiles.length > 0 && (
        <div className="text-terminal-dim">
          Files tracked: <span className="text-terminal-text">{meta.trackedFiles.length}</span>
        </div>
      )}

      {meta.contextFiles && meta.contextFiles.length > 0 && (
        <div className="text-terminal-dim">
          Context files: <span className="text-terminal-text">{meta.contextFiles.length}</span>
        </div>
      )}

      {/* PR Links */}
      {meta.prLinks && meta.prLinks.length > 0 && (
        <div>
          <div className="ui-section-title mb-1">Pull Requests</div>
          <div className="space-y-0.5">
            {meta.prLinks.map((pr) => (
              <a
                key={pr.prUrl}
                href={pr.prUrl}
                target="_blank"
                rel="noopener noreferrer"
                className="block text-terminal-blue hover:underline truncate"
                title={pr.prUrl}
              >
                <span className="text-terminal-green">#{pr.prNumber}</span>{" "}
                {pr.prRepository && <span className="text-terminal-dimmer">{pr.prRepository}</span>}
              </a>
            ))}
          </div>
        </div>
      )}

      <div className="text-terminal-dim leading-relaxed">
        Chars: <span className="text-terminal-green">{fmtNum(stats.promptChars)}</span> prompt
        {" / "}
        <span className="text-terminal-purple">{fmtNum(stats.thinkingChars)}</span> thinking
        {" / "}
        <span className="text-terminal-blue">{fmtNum(stats.responseChars)}</span> response
      </div>

      {stats.compactions && stats.compactions.length > 0 && (
        <div>
          <div className="ui-section-title mb-2">
            Context Compactions ({stats.compactions.length})
          </div>
          <div className="space-y-1">
            {stats.compactions.map((c, i) => (
              <div
                key={i}
                className="text-terminal-dim text-xs flex items-baseline gap-1.5 flex-wrap"
              >
                <span className="text-terminal-orange">●</span>
                <span>{c.trigger}</span>
                {c.preTokens && (
                  <span className="text-terminal-text">{fmtNum(c.preTokens)} tokens</span>
                )}
              </div>
            ))}
          </div>
        </div>
      )}

      {stats.topTools.length > 0 && (
        <div>
          <div className="ui-section-title mb-2">Top Tools</div>
          <div className="space-y-1.5">
            {stats.topTools.map(([name, count]) => (
              <div key={name} className="flex items-center gap-2">
                <span className="text-terminal-text shrink-0 w-20 text-right">{name}</span>
                <div className="flex-1 h-2 rounded-full bg-terminal-surface overflow-hidden">
                  <div
                    className="h-full rounded-full bg-terminal-orange"
                    style={{ width: `${(count / stats.topTools[0][1]) * 100}%` }}
                  />
                </div>
                <span className="text-terminal-dim shrink-0 w-6 text-right tabular-nums">
                  {count}
                </span>
              </div>
            ))}
          </div>
        </div>
      )}

      {(meta.dataSource || meta.dataSourceInfo) && (
        <div>
          <div className="ui-section-title mb-2">Data Source</div>
          <div className="text-terminal-dim">
            <span className="text-terminal-blue">
              {formatReplaySourceLabel(meta.dataSourceInfo?.primary || meta.dataSource)}
            </span>
          </div>
          {meta.dataSourceInfo?.sources && meta.dataSourceInfo.sources.length > 0 && (
            <div className="mt-0.5 space-y-0.5">
              {meta.dataSourceInfo.sources.map((source) => (
                <div key={source} className="text-terminal-dim truncate" title={source}>
                  <span className="text-terminal-green">source:</span> {source}
                </div>
              ))}
            </div>
          )}
          {meta.dataSourceInfo?.supplements && meta.dataSourceInfo.supplements.length > 0 && (
            <div className="mt-0.5 space-y-0.5">
              {meta.dataSourceInfo.supplements.map((source) => (
                <div key={source} className="text-terminal-dim truncate" title={source}>
                  <span className="text-terminal-purple">supplement:</span> {source}
                </div>
              ))}
            </div>
          )}
          {meta.dataSourceInfo?.notes && meta.dataSourceInfo.notes.length > 0 && (
            <div className="mt-0.5 space-y-0.5">
              {meta.dataSourceInfo.notes.map((note) => (
                <div key={note} className="text-terminal-dim truncate" title={note}>
                  <span className="text-terminal-orange">note:</span> {note}
                </div>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export function StatCard({
  label,
  value,
  color,
}: {
  label: string;
  value: number | React.ReactNode;
  color: string;
}) {
  const isNumber = typeof value === "number";
  return (
    <div className="bg-terminal-surface rounded-xl px-3 py-3 shadow-layer-sm">
      <div
        className={`text-xl font-bold ${isNumber ? "tabular-nums" : "truncate w-full"} ${color}`}
        title={typeof value === "string" ? value : undefined}
      >
        {value}
      </div>
      <div className="ui-section-title mt-0.5">{label}</div>
    </div>
  );
}

export function fmtNum(n: number): string {
  if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`;
  if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;
  return n.toString();
}

export function formatDuration(ms?: number): string {
  if (!ms) return "";
  const secs = Math.floor(ms / 1000);
  if (secs < 60) return `${secs}s`;
  const mins = Math.floor(secs / 60);
  if (mins < 60) return `${mins}m ${secs % 60}s`;
  const hrs = Math.floor(mins / 60);
  return `${hrs}h ${mins % 60}m`;
}

/**
 * Fine-grained duration for individual tool calls. Tool calls are usually
 * sub-second so the regular formatDuration ("0s") would be useless.
 */
export function formatToolDuration(ms?: number): string {
  if (!ms || ms < 1) return "";
  if (ms < 1000) return `${Math.round(ms)}ms`;
  if (ms < 10_000) return `${(ms / 1000).toFixed(1)}s`;
  return formatDuration(ms);
}

/**
 * Compact token count: 919 / 1.5K / 12K / 2.3M. Use a "~" prefix in callers
 * since these are heuristic estimates, not exact tokenizer counts.
 */
export function formatTokens(n?: number): string {
  if (!n || n < 1) return "";
  if (n < 1000) return `${n}`;
  if (n < 10_000) return `${(n / 1000).toFixed(1)}K`;
  if (n < 1_000_000) return `${Math.round(n / 1000)}K`;
  return `${(n / 1_000_000).toFixed(1)}M`;
}

function formatGeneratedAt(iso?: string): string {
  if (!iso) return "";
  const date = new Date(iso);
  if (Number.isNaN(date.getTime())) return iso;
  return date.toLocaleString(undefined, {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  });
}
