import { useEffect, useState } from "react";
import { useBackLayer } from "../../app/useBackLayer.js";
import { elapsedSeconds, formatElapsed } from "../../elapsed-time.js";
import { useI18n } from "../../shared/I18nProvider.jsx";
import { CloseIcon, DisclosureIcon, ForwardIcon, TechnicalActivityIcon } from "../../shared/ActionIcons.jsx";
import { activityFiles, activityLogCount, activityTitle, groupTechnicalActivity, technicalGroupLabel, toolCallLabel, visibleActivityItems, visibleActivityText, withFileChangeCount } from "./activity-card.js";
import { setupErrorMessage } from "../setup/setup-errors.js";

const stateFor = (status, t) => status === "completed" ? { label: t("activity.completed"), className: "completed" } : status === "failed" ? { label: t("activity.failed"), className: "failed" } : status === "interrupted" ? { label: t("activity.interrupted"), className: "interrupted" } : status === "waiting_approval" ? { label: t("activity.waitingApproval"), className: "waiting" } : status === "waiting_response" ? { label: t("activity.waitingResponse"), className: "waiting" } : { label: t("activity.running"), className: "running" };
const ACTIVE_ACTIVITY_STATUSES = new Set(["thinking", "running", "waiting_approval", "waiting_response"]);
const iconFor = (kind) => "•";
const labelFor = (kind, t) => kind === "reasoning" ? t("activity.reasoning") : kind === "commandExecution" ? t("activity.command") : kind === "fileChange" ? t("activity.fileChange") : t("activity.tool");

function toolCallName(item, t) {
  return item.toolCall?.tool ?? item.summary ?? toolCallLabel(item, t);
}

function toolCallTitle(item, t) {
  const tool = toolCallName(item, t);
  const status = item.status === "running" ? t("activity.running") : item.status === "failed" ? t("activity.failed") : t("activity.completed");
  return `${tool} ${t("activity.call")} ${status}`;
}

function formatToolArguments(value) {
  if (value == null) return "";
  if (typeof value === "string") return value;
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}

function ToolCallSheet({ item, onClose, t }) {
  const closeSheet = useBackLayer(Boolean(item), onClose, "tool-call-sheet");
  useEffect(() => {
    if (!item) return undefined;
    const closeOnEscape = (event) => { if (event.key === "Escape") closeSheet(); };
    globalThis.addEventListener?.("keydown", closeOnEscape);
    return () => globalThis.removeEventListener?.("keydown", closeOnEscape);
  }, [closeSheet, item]);
  if (!item) return null;
  const args = formatToolArguments(item.toolCall?.arguments);
  const seconds = Number.isFinite(item.durationMs) ? Math.max(0, Math.round(item.durationMs / 100) / 10) : null;
  return <div className="tool-call-sheet-backdrop" onClick={closeSheet}>
    <section className="tool-call-sheet" role="dialog" aria-modal="true" aria-label={t("activity.toolCall")} onClick={(event) => event.stopPropagation()}>
      <div className="tool-call-sheet-handle" aria-hidden="true" />
      <header><strong>{t("activity.toolCall")}</strong><button className="tool-call-sheet-close" type="button" aria-label={t("activity.closeToolCall")} onClick={closeSheet}><CloseIcon /></button></header>
      <div className="tool-call-sheet-body">
        <dl className="tool-call-fields">
          <div><dt>{t("activity.function")}</dt><dd>{toolCallName(item, t)}</dd></div>
          {item.toolCall?.server && <div><dt>{t("activity.server")}</dt><dd>{item.toolCall.server}</dd></div>}
          <div><dt>{t("activity.status")}</dt><dd>{item.status === "running" ? t("activity.running") : item.status === "failed" ? t("activity.failed") : t("activity.completed")}</dd></div>
          {seconds !== null && <div><dt>{t("activity.duration")}</dt><dd>{seconds.toLocaleString()}s</dd></div>}
        </dl>
        {args && <div className="tool-call-arguments"><strong>{t("activity.arguments")}</strong><pre>{args}</pre></div>}
        <ActivityResult item={item} />
      </div>
    </section>
  </div>;
}

function GeneratedImagePreview({ image }) {
  const [open, setOpen] = useState(false);
  const alt = image.name ?? "Generated image";
  const closePreview = () => setOpen(false);
  const dismissPreview = useBackLayer(Boolean(open), closePreview, "generated-image-preview");
  useEffect(() => {
    if (!open) return undefined;
    const closeOnEscape = (event) => { if (event.key === "Escape") dismissPreview(); };
    globalThis.addEventListener?.("keydown", closeOnEscape);
    return () => globalThis.removeEventListener?.("keydown", closeOnEscape);
  }, [dismissPreview, open]);
  return <>
    <button type="button" className="activity-generated-image-button" aria-label={`Open ${alt}`} onClick={() => setOpen(true)}>
      <img className="activity-generated-image" src={image.url} alt={alt} />
    </button>
    {open && <div className="activity-image-lightbox-backdrop" onClick={dismissPreview}>
      <section className="activity-image-lightbox" role="dialog" aria-modal="true" aria-label={alt} onClick={(event) => event.stopPropagation()}>
        <button type="button" className="activity-image-lightbox-close" aria-label={`Close ${alt}`} onClick={dismissPreview}><CloseIcon /></button>
        <img className="activity-image-lightbox-image" src={image.url} alt={alt} />
      </section>
    </div>}
  </>;
}

function ActivityResult({ item }) {
  const text = visibleActivityText(item);
  return <>
    {text && <pre className={item.error ? "activity-result activity-result-error" : "activity-result"}>{text}</pre>}
    {Number.isInteger(item.exitCode) && <p className="activity-exit-code">Exit code: {item.exitCode}</p>}
    {(item.images ?? []).map((image) => <GeneratedImagePreview image={image} key={image.id ?? image.url} />)}
  </>;
}

function ActivityItem({ item, onOpenToolCall, t }) {
  const summary = item.summary ?? labelFor(item.kind, t);
  if (item.toolCall || ["mcpToolCall", "dynamicToolCall", "webSearch"].includes(item.kind)) {
    return <div className="activity-tool-call-result"><button type="button" className="activity-tool-call-button" onClick={() => onOpenToolCall(item)}><span>{toolCallTitle(item, t)}</span><ForwardIcon className="activity-tool-call-arrow" /></button></div>;
  }
  if (item.kind === "commandExecution") return <div className="activity-item technical"><span>{iconFor(item.kind)}</span><details className="activity-command"><summary>{summary}</summary><ActivityResult item={item} /></details></div>;
  return <div className={`activity-item ${item.kind === "agentMessage" ? "commentary" : "technical"}`}><span>{iconFor(item.kind)}</span><div>
    {item.kind !== "agentMessage" && <span className="activity-item-summary">{summary}</span>}
    <ActivityResult item={item} />
  </div></div>;
}

function TechnicalActivityGroup({ items, changedFiles, onOpenChangedFile, onOpenToolCall, t }) {
  const files = activityFiles(items, changedFiles);
  const technicalItems = items.filter((item) => item.kind !== "fileChange");
  return <>
    {technicalItems.length > 0 && <details className="activity-technical-group"><summary><TechnicalActivityIcon />{technicalGroupLabel(technicalItems, t)}<DisclosureIcon className="activity-chevron" /></summary><div className="activity-technical-group-items">
      {technicalItems.map((item) => <ActivityItem item={item} onOpenToolCall={onOpenToolCall} t={t} key={item.id} />)}
    </div></details>}
    {files.length > 0 && <button className="activity-file-group-button" type="button" onClick={() => onOpenChangedFile(files)}><TechnicalActivityIcon className="activity-file-icon activity-technical-icon" /><span>{t("activity.filesChanged", { count: files.length })}</span><ForwardIcon className="activity-file-forward-icon" /></button>}
  </>;
}

function directFileActivityFiles(activityGroups, changedFiles) {
  if (activityGroups.length !== 1 || activityGroups[0].type !== "technicalGroup") return [];
  const items = activityGroups[0].items;
  if (!items.every((item) => item.kind === "fileChange")) return [];
  return activityFiles(items, changedFiles);
}

function displayStateFor(status, t) {
  if (status === "thinking") return { label: t("activity.thinking"), className: "waiting" };
  if (status === "running") return { label: t("activity.running"), className: "running" };
  return stateFor(status, t);
}

export function ActivityCard({ turn, now, onRetry, changedFiles = [], onOpenChangedFile }) {
  const { t } = useI18n();
  const [openToolCall, setOpenToolCall] = useState(null);
  const [activityOpen, setActivityOpen] = useState(() => ACTIVE_ACTIVITY_STATUSES.has(turn.status));
  useEffect(() => {
    if (!ACTIVE_ACTIVITY_STATUSES.has(turn.status)) setActivityOpen(false);
  }, [turn.status]);
  const state = displayStateFor(turn.status, t);
  const seconds = Number.isFinite(turn.activity.durationMs) ? Math.floor(turn.activity.durationMs / 1000) : elapsedSeconds(turn, now);
  const visibleItems = visibleActivityItems(turn.activity.items);
  const activityItems = withFileChangeCount(visibleItems);
  const activityGroups = groupTechnicalActivity(activityItems);
  const logCount = activityLogCount(turn);
  const hasDetails = logCount > 0;
  const activityLabel = activityTitle(turn, logCount, t);
  const directFileFiles = directFileActivityFiles(activityGroups, changedFiles);
  if (directFileFiles.length > 0 && turn.activity.plan.length === 0 && turn.approvals.length === 0 && !turn.error) {
    return <button type="button" className={`activity-card activity-file-direct-button ${state.className}`} onClick={() => onOpenChangedFile(directFileFiles)}>
      <span className="activity-log-label"><TechnicalActivityIcon className="activity-file-icon activity-technical-icon" /><span>{t("activity.filesChanged", { count: directFileFiles.length })}</span><ForwardIcon className="activity-file-forward-icon" /></span>
      <span className="activity-meta"><span className="activity-state"><i aria-hidden="true" />{state.label}</span>{seconds > 0 && <span>{formatElapsed(seconds)}</span>}</span>
    </button>;
  }
  return <details className={`activity-card ${state.className}`} open={activityOpen} onToggle={(event) => setActivityOpen(event.currentTarget.open)}><summary><span className="activity-log-label">{activityLabel}{hasDetails && <DisclosureIcon className="activity-chevron" />}</span><span className="activity-meta"><span className="activity-state"><i aria-hidden="true" />{state.label}</span>{seconds > 0 && <span>{formatElapsed(seconds)}</span>}</span></summary>
    {hasDetails && <div className="activity-details">
      {turn.activity.plan.length > 0 && <ol className="activity-plan">{turn.activity.plan.map((step, index) => <li className={step.status} key={`${step.step}-${index}`}><span>•</span>{step.step}</li>)}</ol>}
      {activityGroups.map((group) => group.type === "technicalGroup"
        ? <TechnicalActivityGroup items={group.items} changedFiles={changedFiles} onOpenChangedFile={onOpenChangedFile} onOpenToolCall={setOpenToolCall} t={t} key={group.key} />
        : <ActivityItem item={group.item} onOpenToolCall={setOpenToolCall} t={t} key={group.key} />)}
      {turn.approvals.filter((a) => a.status !== "pending").map((a) => <div className="activity-item" key={a.id}><span>•</span><strong>{a.title} · {a.status}</strong></div>)}
      {turn.error && <p className="activity-error">{setupErrorMessage(new Error(turn.error), "chat_message_failed")}</p>}
      {turn.status === "failed" && turn.userText && <button className="retry-button" onClick={() => onRetry(turn.userText)}>{t("activity.retry")}</button>}
    </div>}<ToolCallSheet item={openToolCall} onClose={() => setOpenToolCall(null)} t={t} /></details>;
}
