"use client";

/**
 * TerminalPanel
 *
 * Multi-tab terminal panel. Manages multiple PTY sessions via useTerminalSessions,
 * rendering one XTerminal per session and keeping all instances mounted (for
 * scrollback preservation) while switching visibility with display:none.
 *
 * Also renders read-only agent output tabs from the orchestrator SSE stream
 * via useAgentStream. Agent tabs are automatically added when agents are active
 * and can be dismissed when completed or errored.
 *
 * Features:
 * - "+" button to open a new terminal tab
 * - Per-tab close button (terminal) / dismiss button (agent)
 * - Double-click tab label for inline rename (terminal tabs only)
 * - Auto-creates the first terminal session on connect
 * - Connection error state
 * - Agent tabs: read-only, auto-appear, dismissable
 */

import { useState, useEffect, useRef, useCallback } from "react";
import type { ReactElement, CSSProperties, KeyboardEvent } from "react";
import { XTerminal } from "./XTerminal";
import { AgentTerminal } from "./AgentTerminal";
import { useTerminalSessions } from "@/hooks/useTerminalSessions";
import { useAgentStream } from "@/hooks/useAgentStream";

// ==========================================
// Types
// ==========================================

export interface TerminalPanelProps {
  /** Whether the panel is visible */
  open: boolean;
  /** Called when the user closes the panel */
  onClose: () => void;
  /** Authentication token for the WebSocket connection */
  token?: string;
  /** Optional CSS class name */
  className?: string;
}

// ==========================================
// Component
// ==========================================

export function TerminalPanel({
  open,
  onClose,
  token = "",
  className = "",
}: TerminalPanelProps): ReactElement {
  const {
    sessions,
    activeSessionId,
    isConnected,
    connectionError,
    createSession,
    closeSession,
    renameSession,
    setActiveSession,
    sendInput,
    resize,
    registerOutputCallback,
  } = useTerminalSessions({ token });

  // ==========================================
  // Agent stream
  // ==========================================

  const { agents, dismissAgent } = useAgentStream();

  // ==========================================
  // Active tab state (terminal session OR agent)
  // "terminal:<sessionId>" or "agent:<agentId>"
  // ==========================================

  type TabId = string; // prefix-qualified: "terminal:<id>" or "agent:<id>"

  const [activeTabId, setActiveTabId] = useState<TabId | null>(null);

  // Sync activeTabId with the terminal session activeSessionId when no agent tab is selected
  useEffect(() => {
    setActiveTabId((prev) => {
      // If an agent tab is active, don't clobber it
      if (prev?.startsWith("agent:")) return prev;
      // Reflect active terminal session
      if (activeSessionId !== null) return `terminal:${activeSessionId}`;
      return prev;
    });
  }, [activeSessionId]);

  // If the active agent tab is dismissed, fall back to the terminal session
  useEffect(() => {
    if (activeTabId?.startsWith("agent:")) {
      const agentId = activeTabId.slice("agent:".length);
      if (!agents.has(agentId)) {
        setActiveTabId(activeSessionId !== null ? `terminal:${activeSessionId}` : null);
      }
    }
  }, [agents, activeTabId, activeSessionId]);

  // ==========================================
  // Inline rename state
  // ==========================================

  const [editingTabId, setEditingTabId] = useState<string | null>(null);
  const [editingName, setEditingName] = useState("");
  const editInputRef = useRef<HTMLInputElement>(null);

  // Focus the rename input when editing starts
  useEffect(() => {
    if (editingTabId !== null) {
      editInputRef.current?.select();
    }
  }, [editingTabId]);

  // ==========================================
  // Auto-create first session on connect
  // ==========================================

  useEffect(() => {
    if (open && isConnected && sessions.size === 0) {
      createSession({ name: "Terminal 1" });
    }
  }, [open, isConnected, sessions.size, createSession]);

  // ==========================================
  // Tab rename helpers
  // ==========================================

  const commitRename = useCallback((): void => {
    if (editingTabId !== null) {
      const trimmed = editingName.trim();
      if (trimmed.length > 0) {
        renameSession(editingTabId, trimmed);
      }
      setEditingTabId(null);
      setEditingName("");
    }
  }, [editingTabId, editingName, renameSession]);

  const handleTabDoubleClick = useCallback((sessionId: string, currentName: string): void => {
    setEditingTabId(sessionId);
    setEditingName(currentName);
  }, []);

  const handleRenameKeyDown = useCallback(
    (e: KeyboardEvent<HTMLInputElement>): void => {
      if (e.key === "Enter") {
        commitRename();
      } else if (e.key === "Escape") {
        setEditingTabId(null);
        setEditingName("");
      }
    },
    [commitRename]
  );

  // ==========================================
  // Session control helpers
  // ==========================================

  const handleCreateTab = useCallback((): void => {
    const tabNumber = sessions.size + 1;
    createSession({ name: `Terminal ${tabNumber.toString()}` });
  }, [sessions.size, createSession]);

  const handleCloseTab = useCallback(
    (sessionId: string): void => {
      closeSession(sessionId);
    },
    [closeSession]
  );

  const handleRestart = useCallback(
    (sessionId: string, name: string): void => {
      closeSession(sessionId);
      createSession({ name });
    },
    [closeSession, createSession]
  );

  // ==========================================
  // Styles
  // ==========================================

  const panelStyle: CSSProperties = {
    background: "var(--bg-deep)",
    borderTop: "1px solid var(--border)",
    overflow: "hidden",
    flexShrink: 0,
    display: "flex",
    flexDirection: "column",
    height: open ? 280 : 0,
    transition: "height 0.3s ease",
  };

  const headerStyle: CSSProperties = {
    display: "flex",
    alignItems: "center",
    gap: 10,
    padding: "6px 16px",
    borderBottom: "1px solid var(--border)",
    flexShrink: 0,
  };

  const tabBarStyle: CSSProperties = {
    display: "flex",
    gap: 2,
    alignItems: "center",
    flex: 1,
    overflow: "hidden",
  };

  const actionsStyle: CSSProperties = {
    display: "flex",
    gap: 4,
    alignItems: "center",
  };

  const bodyStyle: CSSProperties = {
    flex: 1,
    overflow: "hidden",
    display: "flex",
    flexDirection: "column",
    minHeight: 0,
    position: "relative",
  };

  // ==========================================
  // Agent status dot color
  // ==========================================

  const agentDotColor = (status: string): string => {
    if (status === "running" || status === "spawning") return "var(--success)";
    if (status === "error") return "var(--danger)";
    return "var(--muted)";
  };

  // ==========================================
  // Render
  // ==========================================

  return (
    <div
      className={className}
      style={panelStyle}
      role="region"
      aria-label="Terminal panel"
      aria-hidden={!open}
    >
      {/* Header */}
      <div style={headerStyle}>
        {/* Tab bar */}
        <div style={tabBarStyle} role="tablist" aria-label="Terminal tabs">
          {/* ---- Terminal session tabs ---- */}
          {[...sessions.entries()].map(([sessionId, sessionInfo]) => {
            const tabKey = `terminal:${sessionId}`;
            const isActive = tabKey === activeTabId;
            const isEditing = sessionId === editingTabId;

            const tabStyle: CSSProperties = {
              display: "flex",
              alignItems: "center",
              gap: 4,
              padding: "3px 6px 3px 10px",
              borderRadius: 4,
              fontSize: "0.75rem",
              fontFamily: "var(--mono)",
              color: isActive ? "var(--success)" : "var(--muted)",
              background: isActive ? "var(--surface)" : "transparent",
              border: "none",
              outline: "none",
              flexShrink: 0,
            };

            return (
              <div key={tabKey} style={tabStyle}>
                {isEditing ? (
                  <input
                    ref={editInputRef}
                    value={editingName}
                    onChange={(e): void => {
                      setEditingName(e.target.value);
                    }}
                    onBlur={commitRename}
                    onKeyDown={handleRenameKeyDown}
                    data-testid="tab-rename-input"
                    style={{
                      background: "transparent",
                      border: "none",
                      outline: "1px solid var(--primary)",
                      borderRadius: 2,
                      fontFamily: "var(--mono)",
                      fontSize: "0.75rem",
                      color: "var(--text)",
                      width: `${Math.max(editingName.length, 4).toString()}ch`,
                      padding: "0 2px",
                    }}
                    aria-label="Rename terminal tab"
                  />
                ) : (
                  <button
                    role="tab"
                    aria-selected={isActive}
                    style={{
                      background: "transparent",
                      border: "none",
                      outline: "none",
                      fontFamily: "var(--mono)",
                      fontSize: "0.75rem",
                      color: isActive ? "var(--success)" : "var(--muted)",
                      cursor: "pointer",
                      padding: 0,
                    }}
                    onClick={(): void => {
                      setActiveTabId(tabKey);
                      setActiveSession(sessionId);
                    }}
                    onDoubleClick={(): void => {
                      handleTabDoubleClick(sessionId, sessionInfo.name);
                    }}
                    onMouseEnter={(e): void => {
                      if (!isActive) {
                        (e.currentTarget as HTMLButtonElement).style.color = "var(--text-2)";
                      }
                    }}
                    onMouseLeave={(e): void => {
                      if (!isActive) {
                        (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
                      }
                    }}
                    aria-label={sessionInfo.name}
                  >
                    {sessionInfo.name}
                  </button>
                )}

                {/* Per-tab close button */}
                <button
                  aria-label={`Close ${sessionInfo.name}`}
                  style={{
                    width: 16,
                    height: 16,
                    borderRadius: 3,
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    color: "var(--muted)",
                    cursor: "pointer",
                    background: "transparent",
                    border: "none",
                    outline: "none",
                    padding: 0,
                    flexShrink: 0,
                  }}
                  onClick={(): void => {
                    handleCloseTab(sessionId);
                  }}
                  onMouseEnter={(e): void => {
                    (e.currentTarget as HTMLButtonElement).style.background = "var(--surface)";
                    (e.currentTarget as HTMLButtonElement).style.color = "var(--text)";
                  }}
                  onMouseLeave={(e): void => {
                    (e.currentTarget as HTMLButtonElement).style.background = "transparent";
                    (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
                  }}
                >
                  <svg width="8" height="8" viewBox="0 0 8 8" fill="none" aria-hidden="true">
                    <path
                      d="M1 1L7 7M7 1L1 7"
                      stroke="currentColor"
                      strokeWidth="1.5"
                      strokeLinecap="round"
                    />
                  </svg>
                </button>
              </div>
            );
          })}

          {/* New tab button */}
          <button
            aria-label="New terminal tab"
            style={{
              width: 22,
              height: 22,
              borderRadius: 4,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: "var(--muted)",
              cursor: "pointer",
              background: "transparent",
              border: "none",
              outline: "none",
              padding: 0,
              flexShrink: 0,
            }}
            onClick={handleCreateTab}
            onMouseEnter={(e): void => {
              (e.currentTarget as HTMLButtonElement).style.background = "var(--surface)";
              (e.currentTarget as HTMLButtonElement).style.color = "var(--text)";
            }}
            onMouseLeave={(e): void => {
              (e.currentTarget as HTMLButtonElement).style.background = "transparent";
              (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
            }}
          >
            {/* Plus icon */}
            <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
              <path
                d="M6 1V11M1 6H11"
                stroke="currentColor"
                strokeWidth="1.5"
                strokeLinecap="round"
              />
            </svg>
          </button>

          {/* ---- Agent section divider (only when agents exist) ---- */}
          {agents.size > 0 && (
            <div
              aria-hidden="true"
              style={{
                width: 1,
                height: 16,
                background: "var(--border)",
                marginLeft: 6,
                marginRight: 4,
                flexShrink: 0,
              }}
            />
          )}

          {/* ---- Agent tabs ---- */}
          {[...agents.entries()].map(([agentId, agentSession]) => {
            const tabKey = `agent:${agentId}`;
            const isActive = tabKey === activeTabId;

            const canDismiss =
              agentSession.status === "completed" || agentSession.status === "error";

            const agentTabStyle: CSSProperties = {
              display: "flex",
              alignItems: "center",
              gap: 4,
              padding: "3px 6px 3px 8px",
              borderRadius: 4,
              fontSize: "0.75rem",
              fontFamily: "var(--mono)",
              color: isActive ? "var(--text)" : "var(--muted)",
              background: isActive ? "var(--surface)" : "transparent",
              border: "none",
              outline: "none",
              flexShrink: 0,
            };

            return (
              <div
                key={tabKey}
                style={agentTabStyle}
                data-testid="agent-tab"
                data-agent-id={agentId}
                data-agent-status={agentSession.status}
              >
                {/* Status dot */}
                <span
                  aria-hidden="true"
                  style={{
                    display: "inline-block",
                    width: 6,
                    height: 6,
                    borderRadius: "50%",
                    background: agentDotColor(agentSession.status),
                    flexShrink: 0,
                  }}
                />

                {/* Agent tab button — read-only, no rename */}
                <button
                  role="tab"
                  aria-selected={isActive}
                  style={{
                    background: "transparent",
                    border: "none",
                    outline: "none",
                    fontFamily: "var(--mono)",
                    fontSize: "0.75rem",
                    color: isActive ? "var(--text)" : "var(--muted)",
                    cursor: "pointer",
                    padding: 0,
                    maxWidth: 100,
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                    whiteSpace: "nowrap",
                  }}
                  onClick={(): void => {
                    setActiveTabId(tabKey);
                  }}
                  onMouseEnter={(e): void => {
                    if (!isActive) {
                      (e.currentTarget as HTMLButtonElement).style.color = "var(--text-2)";
                    }
                  }}
                  onMouseLeave={(e): void => {
                    if (!isActive) {
                      (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
                    }
                  }}
                  aria-label={`Agent: ${agentSession.agentType}`}
                >
                  {agentSession.agentType}
                </button>

                {/* Dismiss button — only for completed/error agents */}
                {canDismiss && (
                  <button
                    aria-label={`Dismiss ${agentSession.agentType} agent`}
                    style={{
                      width: 16,
                      height: 16,
                      borderRadius: 3,
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "center",
                      color: "var(--muted)",
                      cursor: "pointer",
                      background: "transparent",
                      border: "none",
                      outline: "none",
                      padding: 0,
                      flexShrink: 0,
                    }}
                    onClick={(): void => {
                      dismissAgent(agentId);
                    }}
                    onMouseEnter={(e): void => {
                      (e.currentTarget as HTMLButtonElement).style.background = "var(--surface)";
                      (e.currentTarget as HTMLButtonElement).style.color = "var(--text)";
                    }}
                    onMouseLeave={(e): void => {
                      (e.currentTarget as HTMLButtonElement).style.background = "transparent";
                      (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
                    }}
                  >
                    <svg width="8" height="8" viewBox="0 0 8 8" fill="none" aria-hidden="true">
                      <path
                        d="M1 1L7 7M7 1L1 7"
                        stroke="currentColor"
                        strokeWidth="1.5"
                        strokeLinecap="round"
                      />
                    </svg>
                  </button>
                )}
              </div>
            );
          })}
        </div>

        {/* Action buttons */}
        <div style={actionsStyle}>
          {/* Close panel button */}
          <button
            aria-label="Close terminal"
            style={{
              width: 22,
              height: 22,
              borderRadius: 4,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: "var(--muted)",
              cursor: "pointer",
              background: "transparent",
              border: "none",
              outline: "none",
              padding: 0,
            }}
            onClick={onClose}
            onMouseEnter={(e): void => {
              (e.currentTarget as HTMLButtonElement).style.background = "var(--surface)";
              (e.currentTarget as HTMLButtonElement).style.color = "var(--text)";
            }}
            onMouseLeave={(e): void => {
              (e.currentTarget as HTMLButtonElement).style.background = "transparent";
              (e.currentTarget as HTMLButtonElement).style.color = "var(--muted)";
            }}
          >
            {/* Close icon */}
            <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
              <path
                d="M1 1L11 11M11 1L1 11"
                stroke="currentColor"
                strokeWidth="1.5"
                strokeLinecap="round"
              />
            </svg>
          </button>
        </div>
      </div>

      {/* Connection error banner */}
      {connectionError !== null && (
        <div
          role="alert"
          style={{
            padding: "4px 16px",
            fontSize: "0.75rem",
            fontFamily: "var(--mono)",
            color: "var(--danger)",
            backgroundColor: "var(--bg-deep)",
            borderBottom: "1px solid var(--border)",
            flexShrink: 0,
          }}
        >
          Connection error: {connectionError}
        </div>
      )}

      {/* Terminal body — keep all XTerminal instances mounted for scrollback */}
      <div style={bodyStyle}>
        {/* ---- Terminal session panels ---- */}
        {[...sessions.entries()].map(([sessionId, sessionInfo]) => {
          const tabKey = `terminal:${sessionId}`;
          const isActive = tabKey === activeTabId;
          const termStyle: CSSProperties = {
            display: isActive ? "flex" : "none",
            flex: 1,
            flexDirection: "column",
            minHeight: 0,
          };

          return (
            <div key={tabKey} style={termStyle}>
              <XTerminal
                sessionId={sessionId}
                sendInput={sendInput}
                resize={resize}
                closeSession={closeSession}
                registerOutputCallback={registerOutputCallback}
                isConnected={isConnected}
                sessionStatus={sessionInfo.status}
                {...(sessionInfo.exitCode !== undefined ? { exitCode: sessionInfo.exitCode } : {})}
                isVisible={isActive && open}
                onRestart={(): void => {
                  handleRestart(sessionId, sessionInfo.name);
                }}
                style={{ flex: 1, minHeight: 0 }}
              />
            </div>
          );
        })}

        {/* ---- Agent session panels ---- */}
        {[...agents.entries()].map(([agentId, agentSession]) => {
          const tabKey = `agent:${agentId}`;
          const isActive = tabKey === activeTabId;
          const agentPanelStyle: CSSProperties = {
            display: isActive ? "flex" : "none",
            flex: 1,
            flexDirection: "column",
            minHeight: 0,
          };

          return (
            <div key={tabKey} style={agentPanelStyle}>
              <AgentTerminal agent={agentSession} style={{ flex: 1, minHeight: 0 }} />
            </div>
          );
        })}

        {/* Empty state — show only when no terminal sessions AND no agent sessions */}
        {sessions.size === 0 && agents.size === 0 && (
          <div
            style={{
              flex: 1,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              color: "var(--muted)",
              fontSize: "0.75rem",
              fontFamily: "var(--mono)",
            }}
          >
            {isConnected ? "Creating terminal..." : (connectionError ?? "Connecting...")}
          </div>
        )}
      </div>
    </div>
  );
}
