/**
 * Session Card Component
 *
 * Individual agent session panel with terminal output,
 * status indicators, and control buttons.
 */

import type { Session, SessionState, TaskRun } from "@coder-studio/core";
import { useAtomValue, useSetAtom, useStore } from "jotai";
import { FlipHorizontal, FlipVertical, GripVertical, X } from "lucide-react";
import type { FC, ReactNode } from "react";
import { useEffect, useRef, useState } from "react";
import { pendingFocusSessionAtom } from "../../../../atoms/app-ui";
import { dispatchCommandAtom } from "../../../../atoms/connection";
import { sessionByIdAtomFamily, sessionsAtom } from "../../../../atoms/sessions";
import { workspaceByIdAtomFamily } from "../../../../atoms/workspaces";
import { Button, IconButton, StatusDot, Tag, Tooltip } from "../../../../components/ui";
import { useTranslation } from "../../../../lib/i18n";
import { useTerminalThemeBackground } from "../../../../theme";
import { bottomPanelActiveTabAtomFamily } from "../../../bottom-panel";
import { pushToastAtom } from "../../../notifications/atoms";
import { PanelHeader } from "../../../shared/components/panel-header";
import { useSupervisor } from "../../../supervisor/actions/use-supervisor";
import { SupervisorCard } from "../../../supervisor/views/shared/supervisor-card";
import { latestVerifyRunAtomFamily, taskStateAtomFamily } from "../../../tasks/atoms";
import {
  terminalActiveIdAtomFamily,
  terminalIdsAtomFamily,
  terminalMetaAtomFamily,
} from "../../../terminal-panel/atoms";
import { XtermHost } from "../../../terminal-panel/views/shared/xterm-host";
import { usePersistWorkspaceLastViewedTarget } from "../../../workspace/actions/use-persist-workspace-last-viewed-target";
import { useWorkspaceUiStatePersistence } from "../../../workspace/actions/use-workspace-ui-state-persistence";
import type { PaneDropIntent, PaneDropPlacement } from "../../actions/pane-drag-types";
import { usePaneActions } from "../../actions/use-pane-actions";
import type { PaneDragSourceSnapshot } from "../../actions/use-pane-drag-controller";
import { usePaneDragEnabled } from "../../actions/use-pane-drag-enabled";
import { useSessionActions } from "../../actions/use-session-actions";

type SessionCardAction = () => void | Promise<void>;

interface SessionCardDragState {
  isDragging: boolean;
  isActiveDropTarget: boolean;
  hoverPlacement: PaneDropPlacement | null;
}

interface SessionCardProps {
  paneId?: string;
  dragState?: SessionCardDragState;
  sessionId: string;
  showHeaderActions?: boolean;
  showSupervisorInline?: boolean;
  terminalReadOnlyOverride?: boolean;
  headerAccessory?: ReactNode;
  onClose?: SessionCardAction;
  onPaneDragStart?: (source: PaneDragSourceSnapshot) => void;
  onPaneDrop?: (intent: PaneDropIntent) => void;
  onSplitHorizontal?: SessionCardAction;
  onSplitVertical?: SessionCardAction;
}

/**
 * Session Card
 *
 * PRD §8.3.1:
 *   - Header: status dot, title, provider badge, status label, actions
 *   - Terminal area (xterm.js)
 */
export const SessionCard: FC<SessionCardProps> = ({
  paneId,
  dragState,
  sessionId,
  showHeaderActions = true,
  showSupervisorInline = true,
  terminalReadOnlyOverride,
  headerAccessory,
  onClose,
  onPaneDragStart,
  onPaneDrop: _onPaneDrop,
  onSplitHorizontal,
  onSplitVertical,
}) => {
  const t = useTranslation();
  const session = useAtomValue(sessionByIdAtomFamily(sessionId));
  const workspaceIdForTasks = session?.workspaceId ?? "__workspace_empty__";
  const taskState = useAtomValue(taskStateAtomFamily(workspaceIdForTasks));
  const latestVerifyRun = useAtomValue(latestVerifyRunAtomFamily(workspaceIdForTasks));
  const dispatch = useAtomValue(dispatchCommandAtom);
  const setSessions = useSetAtom(sessionsAtom);
  const setTaskState = useSetAtom(taskStateAtomFamily(workspaceIdForTasks));
  const setBottomPanelTab = useSetAtom(bottomPanelActiveTabAtomFamily(workspaceIdForTasks));
  const setActiveTerminalId = useSetAtom(terminalActiveIdAtomFamily(workspaceIdForTasks));
  const pushToast = useSetAtom(pushToastAtom);
  const store = useStore();
  const themeBackground = useTerminalThemeBackground();
  const workspace = useAtomValue(
    workspaceByIdAtomFamily(session?.workspaceId ?? "__workspace_empty__")
  );
  const pendingFocus = useAtomValue(pendingFocusSessionAtom);
  const setPendingFocus = useSetAtom(pendingFocusSessionAtom);
  const supportsPaneDrag = usePaneDragEnabled();

  const cardRef = useRef<HTMLDivElement | null>(null);
  const [highlight, setHighlight] = useState(false);
  useSupervisor(session);
  const paneActions = usePaneActions(session?.workspaceId ?? "__workspace_empty__");
  const sessionActions = useSessionActions();
  const { persistUiState } = useWorkspaceUiStatePersistence(
    session?.workspaceId ?? "__workspace_empty__"
  );
  const persistLastViewedTarget = usePersistWorkspaceLastViewedTarget();

  useEffect(() => {
    if (pendingFocus !== sessionId) {
      return;
    }
    const node = cardRef.current;
    if (node) {
      node.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
    }
    setHighlight(true);
    setPendingFocus(null);
    const timer = setTimeout(() => setHighlight(false), 1_400);
    return () => clearTimeout(timer);
  }, [pendingFocus, sessionId, setPendingFocus]);

  if (!session) {
    return null;
  }

  const sessionTitle = session.title?.trim() || formatSessionLabel(session.id);
  const sessionTitleTooltip = session.firstSubmittedUserInput?.trim();
  const providerLabel = formatProviderLabel(session.providerId);
  const sessionStateLabel = formatSessionStateLabel(session.state, t);
  const terminalReadOnly = terminalReadOnlyOverride ?? !isSessionInteractive(session.state);
  const isActiveSession = workspace?.uiState.activeSessionId === session.id;
  const isRunning = session.state === "running";
  const dragOverlayPlacement = dragState?.isActiveDropTarget ? dragState.hoverPlacement : null;
  const verifyTask = taskState.tasks.find(
    (task) => task.kind === "verify" || task.id === latestVerifyRun?.taskId
  );

  const activateVerifyTerminal = (run: TaskRun) => {
    const title = `Task: ${verifyTask?.label ?? "Verify"}`;
    store.set(terminalMetaAtomFamily(run.terminalId), {
      id: run.terminalId,
      workspaceId: session.workspaceId,
      kind: "task",
      alive: run.status === "running" || run.status === "queued",
      exitCode: run.exitCode,
      title,
    });
    store.set(terminalIdsAtomFamily(session.workspaceId), (current) =>
      current.includes(run.terminalId) ? current : [...current, run.terminalId]
    );
    setActiveTerminalId(run.terminalId);
    setBottomPanelTab("terminal");
  };

  const rerunVerify = async () => {
    if (!verifyTask) {
      pushToast({
        kind: "info",
        title: t("tasks.title"),
        body: t("tasks.no_verify_task"),
      });
      return null;
    }

    const result = await dispatch<TaskRun>("task.rerun", {
      workspaceId: session.workspaceId,
      taskId: verifyTask.id,
      themeBackground,
    });
    if (!result.ok || !result.data) {
      pushToast({
        kind: "error",
        title: t("tasks.run_failed_title"),
        body: result.error?.message ?? t("tasks.run_failed_body"),
      });
      return null;
    }

    activateVerifyTerminal(result.data);
    setTaskState((previous) => ({
      ...previous,
      runs: [result.data!, ...previous.runs.filter((run) => run.taskId !== verifyTask.id)],
    }));
    return result.data;
  };

  const handleClosedSessionContinue = async () => {
    const createResult = await dispatch<Session>("session.create", {
      workspaceId: session.workspaceId,
      providerId: session.providerId,
      themeBackground,
    });
    if (!createResult.ok || !createResult.data) {
      return;
    }

    const nextSession = createResult.data;
    setSessions((prev) => ({
      ...prev,
      [nextSession.id]: nextSession,
    }));
    paneActions.replaceSession(session.id, nextSession.id);
    void persistLastViewedTarget({
      workspaceId: session.workspaceId,
      sessionId: nextSession.id,
    });
    void persistUiState({ activeSessionId: nextSession.id });
    const removeResult = await dispatch<void>("session.remove", { sessionId: session.id });
    if (!removeResult.ok) {
      console.error("Failed to remove closed session after relaunch:", removeResult.error?.message);
    }
  };

  const handleClosedSessionClose = async () => {
    if (onClose) {
      await onClose();
      return;
    }

    paneActions.closeSessionPane(session.id);
    await sessionActions.closeSession(session.id, "draft");
  };

  const handleCardClick = (event: React.MouseEvent<HTMLDivElement>) => {
    const target = event.target;
    if (!(target instanceof HTMLElement)) {
      return;
    }

    if (target.closest('button, a, input, textarea, select, [role="button"]')) {
      return;
    }

    if (workspace?.uiState.activeSessionId === session.id) {
      return;
    }

    void persistLastViewedTarget({
      workspaceId: session.workspaceId,
      sessionId: session.id,
    });
    void persistUiState({ activeSessionId: session.id });
  };

  return (
    <div
      ref={cardRef}
      className={`session-card agent-pane${isActiveSession ? " session-card--active" : ""}${highlight ? " session-card--focus-pulse" : ""}${isRunning ? " session-card--running" : ""}${dragState?.isDragging ? " session-card--dragging" : ""}${dragState?.isActiveDropTarget ? " session-card--drop-target" : ""}`}
      data-pane-id={paneId}
      data-session-id={sessionId}
      onClick={handleCardClick}
    >
      {dragOverlayPlacement ? (
        <div className={`pane-drop-overlay pane-drop-overlay--${dragOverlayPlacement}`}>
          {dragOverlayPlacement === "center" ? (
            <div className="pane-drop-overlay__center">{t("agent_panes.swap")}</div>
          ) : null}
        </div>
      ) : null}

      <PanelHeader
        className={isRunning ? "session-header--running" : undefined}
        title={sessionTitle}
        titleTooltip={sessionTitleTooltip}
        metaPlacement="inline"
        status={
          <StatusDot
            tone={getSessionDotTone(session.state)}
            pulse={shouldPulseSessionDot(session.state)}
            className={`session-dot ${getSessionDotClass(session.state)}`}
          />
        }
        meta={
          <div className="session-title-row">
            <Tag color="blue" className="session-provider-badge">
              {providerLabel}
            </Tag>
            <Tag
              color={getSessionTagColor(session.state)}
              className="session-state-badge"
              caps={false}
            >
              {sessionStateLabel}
            </Tag>
          </div>
        }
        actions={
          showHeaderActions || headerAccessory ? (
            <div className="session-header-right">
              {headerAccessory ? (
                <div className="session-header-accessory">{headerAccessory}</div>
              ) : null}

              {showHeaderActions ? (
                <div className="session-header-actions">
                  {supportsPaneDrag ? (
                    <Tooltip content={t("agent_panes.drag_pane")}>
                      <IconButton
                        aria-label={t("agent_panes.drag_pane")}
                        className="session-action-btn session-action-btn-drag"
                        data-session-action="drag"
                        icon={<GripVertical size={13} />}
                        onPointerDown={(event) => {
                          event.preventDefault();
                          event.stopPropagation();

                          if (event.pointerType === "touch") {
                            return;
                          }

                          if (!paneId) {
                            return;
                          }

                          onPaneDragStart?.({
                            paneId,
                            sessionId: session.id,
                            title: sessionTitle,
                            providerLabel,
                          });
                        }}
                        size="sm"
                      />
                    </Tooltip>
                  ) : null}
                  <Tooltip content={t("agent_panes.split_horizontal")}>
                    <IconButton
                      aria-label={t("agent_panes.split_horizontal")}
                      className="session-action-btn"
                      data-session-action="split-horizontal"
                      icon={<FlipHorizontal size={13} />}
                      onClick={() => onSplitHorizontal?.()}
                      size="sm"
                    />
                  </Tooltip>
                  <Tooltip content={t("agent_panes.split_vertical")}>
                    <IconButton
                      aria-label={t("agent_panes.split_vertical")}
                      className="session-action-btn"
                      data-session-action="split-vertical"
                      icon={<FlipVertical size={13} />}
                      onClick={() => onSplitVertical?.()}
                      size="sm"
                    />
                  </Tooltip>
                  <Tooltip content={t("action.close")}>
                    <IconButton
                      aria-label={t("action.close")}
                      className="session-action-btn session-action-btn-close"
                      data-session-action="close"
                      icon={<X size={14} />}
                      onClick={() => void onClose?.()}
                      size="sm"
                    />
                  </Tooltip>
                </div>
              ) : null}
            </div>
          ) : null
        }
      />

      {showSupervisorInline &&
      session.capability === "full" &&
      session.state !== "draft" &&
      session.state !== "ended" ? (
        <>
          <SupervisorCard sessionId={session.id} workspaceId={session.workspaceId} />
        </>
      ) : null}

      {latestVerifyRun ? (
        <div className={`session-card-verify session-card-verify--${latestVerifyRun.status}`}>
          <span>
            {t("tasks.last_verify", {
              status: t(`tasks.status_${latestVerifyRun.status}`),
            })}
          </span>
          <span className="session-card-verify-command">
            {[latestVerifyRun.command, ...latestVerifyRun.args].join(" ")}
            {latestVerifyRun.exitCode !== undefined ? ` · exit ${latestVerifyRun.exitCode}` : ""}
          </span>
          <div className="session-card-verify-actions">
            <Button
              size="sm"
              variant="ghost"
              onClick={() => activateVerifyTerminal(latestVerifyRun)}
            >
              {t("tasks.view_output")}
            </Button>
            <Button size="sm" variant="ghost" onClick={() => void rerunVerify()}>
              {t("tasks.rerun_verify")}
            </Button>
          </div>
        </div>
      ) : null}

      <div className="session-terminal">
        <XtermHost
          closedSessionProviderLabel={providerLabel}
          onClosedSessionClose={() => {
            void handleClosedSessionClose();
          }}
          onClosedSessionContinue={() => {
            void handleClosedSessionContinue();
          }}
          terminalId={session.terminalId}
          workspaceId={session.workspaceId}
          readOnly={terminalReadOnly}
          isActiveSession={isActiveSession}
          terminalKind="agent"
        />
      </div>
    </div>
  );
};

function getSessionDotClass(state: SessionState) {
  switch (state) {
    case "starting":
      return "session-dot-starting";
    case "running":
      return "session-dot-running";
    case "ended":
      return "session-dot-complete";
    default:
      return "session-dot-idle";
  }
}

function getSessionDotTone(state: SessionState): "success" | "warning" | "info" | "neutral" {
  switch (state) {
    case "starting":
      return "warning";
    case "running":
      return "info";
    case "ended":
      return "success";
    default:
      return "neutral";
  }
}

function shouldPulseSessionDot(state: SessionState) {
  switch (state) {
    case "starting":
    case "running":
      return true;
    default:
      return false;
  }
}

function getSessionTagColor(state: SessionState): "amber" | "green" | "blue" | "neutral" {
  switch (state) {
    case "starting":
      return "amber";
    case "running":
      return "green";
    case "ended":
      return "blue";
    default:
      return "neutral";
  }
}

function formatSessionLabel(sessionId: string) {
  const numericId = sessionId.match(/(\d+)/)?.[1];

  if (numericId) {
    return `SESSION-${numericId.slice(-2).padStart(2, "0")}`;
  }

  return sessionId.replace(/[_-]/g, " ").toUpperCase();
}

function formatSessionStateLabel(
  state: SessionState,
  t: (key: string, params?: Record<string, string | number>) => string
) {
  const key = `session.state.${state}`;
  const translated = t(key);
  return translated === key
    ? state.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase())
    : translated;
}

function formatProviderLabel(providerId: string) {
  return providerId.replace(/\b\w/g, (char) => char.toUpperCase());
}

function isSessionInteractive(state: SessionState) {
  return state === "running" || state === "idle" || state === "starting";
}

export default SessionCard;
