import React, { useEffect, useCallback, useRef } from 'react';
import { Terminal } from './components/Terminal/Terminal';
import { Sidebar } from './components/Sidebar/Sidebar';
import { TabBar } from './components/TabBar/TabBar';
import { AgentSettingsModal } from './components/Settings/AgentSettingsModal';
import { useTabs } from './hooks/useTabs';
import { createEntry } from './hooks/useTerminal';
import { agentSettingsBridge } from './lib/agentSettingsBridge';
import { terminalBridge } from './lib/terminalBridge';
import { AgentConfigStatus } from './types/agentSettings';
import './App.css';

function App() {
  const tabs = useTabs();
  const [sidebarOpen, setSidebarOpen] = React.useState(true);
  const [isProcessing, setIsProcessing] = React.useState(false);
  const [agentStatus, setAgentStatus] = React.useState<AgentConfigStatus | null>(null);
  const [isSettingsOpen, setIsSettingsOpen] = React.useState(false);
  const commandHistoryRefs = useRef<Record<string, string[]>>({});
  const commandIndexRefs = useRef<Record<string, number>>({});

  const getActiveHistory = () => {
    return tabs.activeWorkspace?.history || [];
  };

  const getActiveCommandHistory = () => {
    return commandHistoryRefs.current[tabs.activeWorkspaceId] || [];
  };

  const pushCommandHistory = useCallback((workspaceId: string, command: string) => {
    if (!commandHistoryRefs.current[workspaceId]) {
      commandHistoryRefs.current[workspaceId] = [];
    }
    commandHistoryRefs.current[workspaceId].push(command);
    commandIndexRefs.current[workspaceId] = -1;
  }, []);

  const clearWorkspaceSession = useCallback((workspaceId: string) => {
    tabs.clearWorkspace(workspaceId);
    tabs.setWorkspaceSession(workspaceId, undefined);
    commandIndexRefs.current[workspaceId] = -1;
  }, [tabs]);

  const refreshAgentStatus = useCallback(async () => {
    const status = await agentSettingsBridge.getStatus();
    setAgentStatus(status);
    return status;
  }, []);

  const handleAgentStatusChange = useCallback((status: AgentConfigStatus) => {
    setAgentStatus(status);
  }, []);

  const handleOpenSettings = useCallback(async () => {
    try {
      await refreshAgentStatus();
    } finally {
      setIsSettingsOpen(true);
    }
  }, [refreshAgentStatus]);

  const handleCommand = useCallback(async (command: string) => {
    const trimmedCommand = command.trim();
    const workspaceId = tabs.activeWorkspaceId;
    const currentWorkspace = tabs.workspaces.find(
      (workspace) => workspace.id === workspaceId,
    );
    const isSlashCommand = trimmedCommand.startsWith('/');

    if (!trimmedCommand) {
      return;
    }

    if (trimmedCommand === '/clear' || trimmedCommand.toLowerCase() === 'clear') {
      clearWorkspaceSession(workspaceId);
      return;
    }

    pushCommandHistory(workspaceId, trimmedCommand);
    setIsProcessing(true);

    if (isSlashCommand) {
      // Slash commands intentionally reset the transcript and session before rendering a fresh result.
      const commandEntry = createEntry({ type: 'command', content: trimmedCommand });
      clearWorkspaceSession(workspaceId);
      tabs.appendWorkspaceEntry(workspaceId, commandEntry);

      try {
        const response = await terminalBridge.executeTerminalCommand({
          workspaceId,
          input: trimmedCommand,
        });

        tabs.appendWorkspaceEntry(
          workspaceId,
          createEntry(
            response.kind === 'text'
              ? { type: 'response', content: response.content }
              : { type: 'panel', content: response.panel },
          ),
        );
      } catch (error) {
        tabs.appendWorkspaceEntry(
          workspaceId,
          createEntry({
            type: 'error',
            content: error instanceof Error ? error.message : 'Command execution failed.',
          }),
        );
      } finally {
        setIsProcessing(false);
      }

      return;
    }

    // Plain text keeps the current workspace conversation alive and streams into a placeholder response entry.
    const commandEntry = createEntry({ type: 'command', content: trimmedCommand });
    const responseEntry = createEntry({ type: 'response', content: '' });

    tabs.appendWorkspaceEntry(workspaceId, commandEntry);
    tabs.appendWorkspaceEntry(workspaceId, responseEntry);

    try {
      const start = await terminalBridge.startChatStream(
        {
          workspaceId,
          sessionId: currentWorkspace?.chatSessionId,
          prompt: trimmedCommand,
          agentProfile: 'interactiveChat',
        },
        {
          onDelta: (event) => {
            // Update only the originating entry so workspace switches do not disrupt the active stream.
            tabs.updateWorkspaceEntry(workspaceId, responseEntry.id, (entry) => ({
              ...entry,
              content: typeof entry.content === 'string' ? `${entry.content}${event.delta}` : event.delta,
              timestamp: new Date(),
            }));
          },
          onResult: (event) => {
            tabs.setWorkspaceSession(workspaceId, event.sessionId);
            tabs.updateWorkspaceEntry(workspaceId, responseEntry.id, (entry) => ({
              ...entry,
              type: 'response',
              content: event.reply,
              timestamp: new Date(),
            }));
            setIsProcessing(false);
          },
          onError: (event) => {
            tabs.updateWorkspaceEntry(workspaceId, responseEntry.id, (entry) => ({
              ...entry,
              type: 'error',
              content: event.message,
              timestamp: new Date(),
            }));
            setIsProcessing(false);
          },
        }
      );

      tabs.setWorkspaceSession(workspaceId, start.sessionId);
    } catch (error) {
      tabs.updateWorkspaceEntry(workspaceId, responseEntry.id, (entry) => ({
        ...entry,
        type: 'error',
        content: error instanceof Error ? error.message : 'Chat stream failed.',
        timestamp: new Date(),
      }));
      setIsProcessing(false);
    }
  }, [tabs, clearWorkspaceSession, pushCommandHistory]);

  // Command history navigation
  // Accesses from END of array (most recent commands first)
  // Index -1 = current input, 0 = most recent, 1 = second most recent, etc.
  const getPreviousCommand = useCallback(() => {
    const history = getActiveCommandHistory();
    const currentIndex = commandIndexRefs.current[tabs.activeWorkspaceId] || -1;

    // Up arrow: go BACK in history (toward older commands)
    if (currentIndex < history.length - 1) {
      const newIndex = currentIndex + 1;
      commandIndexRefs.current[tabs.activeWorkspaceId] = newIndex;
      return history[history.length - 1 - newIndex];
    }
    return null;
  }, [tabs.activeWorkspaceId]);

  const getNextCommand = useCallback(() => {
    const history = getActiveCommandHistory();
    const currentIndex = commandIndexRefs.current[tabs.activeWorkspaceId] || -1;

    // Down arrow: go FORWARD in history (toward newer commands)
    if (currentIndex > 0) {
      const newIndex = currentIndex - 1;
      commandIndexRefs.current[tabs.activeWorkspaceId] = newIndex;
      return history[history.length - 1 - newIndex];
    } else if (currentIndex === 0) {
      // At most recent command, return to current input
      commandIndexRefs.current[tabs.activeWorkspaceId] = -1;
      return '';
    }
    return null;
  }, [tabs.activeWorkspaceId]);

  const resetCommandIndex = useCallback(() => {
    commandIndexRefs.current[tabs.activeWorkspaceId] = -1;
  }, [tabs.activeWorkspaceId]);

  const outputRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    let active = true;

    void refreshAgentStatus()
      .then(() => {
        if (!active) {
          return;
        }
      })
      .catch(() => {
        if (active) {
          setAgentStatus(null);
        }
      });

    return () => {
      active = false;
    };
  }, [refreshAgentStatus]);

  useEffect(() => {
    tabs.workspaces.forEach((workspace) => {
      commandHistoryRefs.current[workspace.id] ??= [];
      commandIndexRefs.current[workspace.id] ??= -1;
    });
  }, [tabs.workspaces]);

  const clearTerminal = useCallback(() => {
    clearWorkspaceSession(tabs.activeWorkspaceId);
  }, [clearWorkspaceSession, tabs.activeWorkspaceId]);

  const handleCreateWorkspace = useCallback(() => {
    tabs.createWorkspace();
  }, [tabs]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 't') {
        e.preventDefault();
        handleCreateWorkspace();
      }

      if ((e.metaKey || e.ctrlKey) && e.key === 'w') {
        e.preventDefault();
        tabs.closeWorkspace(tabs.activeWorkspaceId);
      }

      if ((e.metaKey || e.ctrlKey) && e.key === 'b') {
        e.preventDefault();
        setSidebarOpen(prev => !prev);
      }

      if ((e.metaKey || e.ctrlKey) && e.key === 'l') {
        e.preventDefault();
        clearTerminal();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [tabs, clearTerminal, handleCreateWorkspace]);

  useEffect(() => {
    return () => {
      // Release shared Tauri listeners when the app shell unmounts.
      void terminalBridge.dispose();
    };
  }, []);

  const tabBarTabs = tabs.workspaces.map(w => ({
    id: w.id,
    name: w.name,
    isActive: w.id === tabs.activeWorkspaceId
  }));

  return (
    <div className="flex h-screen bg-[#0a0a0a]">
      {/* Sidebar */}
      <Sidebar
        isOpen={sidebarOpen}
        onToggle={() => setSidebarOpen(!sidebarOpen)}
        onCommand={handleCommand}
      />

      {/* Main Terminal Area */}
      <div className={`flex-1 ${sidebarOpen ? 'ml-0' : ''} transition-all flex flex-col`}>
        {/* Tab Bar */}
        <TabBar
          tabs={tabBarTabs}
          onTabClick={(id) => tabs.setActiveWorkspace(id)}
          onTabClose={(id) => tabs.closeWorkspace(id)}
          onNewTab={handleCreateWorkspace}
          onOpenSettings={() => {
            void handleOpenSettings();
          }}
          isAgentReady={Boolean(agentStatus?.configured)}
          onTabRename={(id, name) => tabs.renameWorkspace(id, name)}
        />

        {/* Terminal */}
        <Terminal
          history={getActiveHistory()}
          isProcessing={isProcessing}
          outputRef={outputRef}
          onSubmit={handleCommand}
          getPreviousCommand={getPreviousCommand}
          getNextCommand={getNextCommand}
          resetCommandIndex={resetCommandIndex}
        />
      </div>

      <AgentSettingsModal
        isOpen={isSettingsOpen}
        status={agentStatus}
        onClose={() => setIsSettingsOpen(false)}
        onStatusChange={handleAgentStatusChange}
      />
    </div>
  );
}

export default App;
