import React, { useCallback, useEffect, useRef } from 'react';
import { Sidebar } from './components/Sidebar/Sidebar';
import { ConfirmDialog } from './components/Settings/ConfirmDialog';
import { TabBar } from './components/TabBar/TabBar';
import { Terminal } from './components/Terminal/Terminal';
import { useAppShortcuts } from './hooks/useAppShortcuts';
import { useChatHistory } from './hooks/useChatHistory';
import { usePortfolioWorkflow } from './hooks/usePortfolioWorkflow';
import { useTabs } from './hooks/useTabs';
import { useTerminalOrchestrator } from './hooks/useTerminalOrchestrator';
import { useTickerHistory } from './hooks/useTickerHistory';
import { useWorkspacePreferences } from './hooks/useWorkspacePreferences';
import { agentSettingsBridge } from './lib/agentSettingsBridge';
import { terminalBridge } from './lib/terminalBridge';
import { AgentConfigStatus } from './types/agentSettings';
import { ResearchNavigationIntent } from './types/research';
import { ChatHistoryEntry } from './types/terminal';
import './App.css';

// Error Boundary Component for catching React rendering errors
class SettingsErrorBoundary extends React.Component<
  { children: React.ReactNode },
  { hasError: boolean; error: Error | null }
> {
  constructor(props: { children: React.ReactNode }) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('SettingsPage Error Boundary caught an error:', error);
    console.error('Error Info:', errorInfo);
    console.error('Component Stack:', errorInfo.componentStack);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="flex h-screen w-screen items-center justify-center bg-term-bg text-term-text">
          <div className="max-w-2xl rounded-lg border border-term-border bg-term-surface p-8 shadow-lg">
            <h1 className="mb-4 text-2xl font-mono font-semibold text-negative">
              Settings Page Error
            </h1>
            <p className="mb-4 font-mono text-term-text-muted">
              The settings page encountered an unexpected error. Please check the
              browser console for details.
            </p>
            {this.state.error && (
              <details className="mb-4">
                <summary className="cursor-pointer font-mono text-sm text-term-text-muted hover:text-term-text">
                  Error details
                </summary>
                <pre className="mt-2 overflow-auto rounded bg-term-bg p-4 text-xs font-mono text-negative">
                  {this.state.error.toString()}
                  {this.state.error.stack}
                </pre>
              </details>
            )}
            <button
              type="button"
              onClick={() => window.location.reload()}
              className="rounded border border-info bg-term-highlight px-4 py-2 font-mono text-sm text-info transition-colors hover:brightness-110"
            >
              Reload Application
            </button>
          </div>
        </div>
      );
    }

    return this.props.children;
  }
}

type AppView = 'terminal' | 'research' | 'settings';

const ResearchScreen = React.lazy(() =>
  import('./components/Research/ResearchScreen').then((module) => ({
    default: module.ResearchScreen,
  })),
);

const SettingsPage = React.lazy(() =>
  import('./components/Settings/SettingsPage').then((module) => ({
    default: module.SettingsPage,
  })),
);

function App() {
  const tabs = useTabs();
  const tickerHistory = useTickerHistory();
  const portfolioWorkflow = usePortfolioWorkflow();
  const chatHistory = useChatHistory();
  const workspacePreferences = useWorkspacePreferences();
  const [activeView, setActiveView] = React.useState<AppView>('terminal');
  const [researchIntent, setResearchIntent] = React.useState<ResearchNavigationIntent | null>(null);
  const [agentStatus, setAgentStatus] = React.useState<AgentConfigStatus | null>(null);
  const [sidebarOpen, setSidebarOpen] = React.useState(true);
  const hasAutoLoadedPortfolioRef = useRef(false);
  const activePortfolioWorkflow = portfolioWorkflow.readWorkflow(tabs.activeWorkspaceId);
  const activeTerminalState = tabs.activeWorkspace?.terminal;
  const activePendingApproval = activeTerminalState?.pendingApproval ?? null;

  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 {
      portfolioWorkflow.exitPortfolioMode(tabs.activeWorkspaceId);
      setActiveView('settings');
    }
  }, [portfolioWorkflow, refreshAgentStatus, tabs.activeWorkspaceId]);

  const handleReturnToTerminal = useCallback(() => {
    setActiveView('terminal');
  }, []);

  const handleOpenResearch = useCallback(
    (intent: ResearchNavigationIntent = {}) => {
      setResearchIntent(intent);
      setActiveView('research');
    },
    [],
  );

  const {
    cancelWorkspaceRequest,
    commandInputRef,
    clearWorkspaceSession,
    handleClearPortfolioAction,
    handleCommand,
    handleStartPortfolioAction,
    handleUpdatePortfolioDraft,
    resetCommandIndex,
    resolvePendingAgentApproval,
    runCommand,
  } = useTerminalOrchestrator({
    tabs,
    tickerHistory,
    portfolioWorkflow,
    setActiveView,
    chatHistory,
  });

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

  const handleCloseWorkspace = useCallback(
    (workspaceId: string) => {
      const workspace = tabs.workspaces.find((candidate) => candidate.id === workspaceId);
      if (!workspace) {
        return;
      }

      void (async () => {
        if (workspace.terminal.activeRequest?.kind === 'chat') {
          try {
            await cancelWorkspaceRequest(workspaceId);
          } catch {
            // Closing the workspace should not be blocked by cancellation transport errors.
          }
        }

        tabs.closeWorkspace(workspaceId);
      })();
    },
    [cancelWorkspaceRequest, tabs],
  );

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

  const cloneTranscript = (entries: ChatHistoryEntry['transcript']): import('./types/terminal').TerminalEntry[] =>
    entries.map((entry) => ({
      ...entry,
      timestamp: entry.timestamp ? new Date(entry.timestamp) : new Date(),
    }));

  const handleRestoreChatHistory = useCallback((entry: ChatHistoryEntry) => {
    setActiveView('terminal');

    if (workspacePreferences.preferences.chatHistoryRestoreTarget === 'newTab') {
      const workspaceId = tabs.createWorkspace({
        name: entry.title || 'Restored Chat',
        terminal: {
          history: cloneTranscript(entry.transcript),
          chatSessionId: undefined,
          inputDraft: '',
          isProcessing: false,
          activeRequest: null,
          pendingApproval: null,
          scrollTop: 0,
          stickToBottom: true,
          collapsedThinkingEntryIds: [],
        },
      });
      tabs.setActiveWorkspace(workspaceId);
      return;
    }

    tabs.restoreWorkspaceTranscript(
      tabs.activeWorkspaceId,
      cloneTranscript(entry.transcript),
    );
  }, [tabs, workspacePreferences.preferences.chatHistoryRestoreTarget]);

  useAppShortcuts({
    activeView,
    activeWorkspaceId: tabs.activeWorkspaceId,
    commandInputRef,
    isProcessing: activeTerminalState?.isProcessing ?? false,
    onClearTerminal: clearTerminal,
    onCloseWorkspace: handleCloseWorkspace,
    onCreateWorkspace: handleCreateWorkspace,
    onOpenResearch: () => {
      handleOpenResearch();
    },
    onOpenSettings: () => {
      void handleOpenSettings();
    },
    onToggleSidebar: () => setSidebarOpen((prev) => !prev),
  });

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

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

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

  useEffect(() => {
    return () => {
      void terminalBridge.dispose();
    };
  }, []);

  useEffect(() => {
    if (
      hasAutoLoadedPortfolioRef.current ||
      activeView !== 'terminal' ||
      activeTerminalState?.isProcessing
    ) {
      return;
    }

    hasAutoLoadedPortfolioRef.current = true;
    // Reset portfolio loading state before triggering command
    portfolioWorkflow.resetPortfolioLoading(tabs.activeWorkspaceId);
    void handleCommand(tabs.activeWorkspaceId, '/portfolio');
  }, [
    activeTerminalState?.isProcessing,
    activeView,
    handleCommand,
    portfolioWorkflow,
    tabs.activeWorkspaceId,
  ]);

  // Sync portfolio names from workflow to workspaces
  React.useEffect(() => {
    tabs.workspaces.forEach((workspace) => {
      const workflow = portfolioWorkflow.readWorkflow(workspace.id);
      if (workflow.portfolioName !== workspace.portfolioName) {
        tabs.setPortfolioName(workspace.id, workflow.portfolioName);
      }
    });
  }, [portfolioWorkflow, tabs.workspaces, tabs.setPortfolioName]);

  const tabBarTabs = tabs.workspaces.map((workspace) => {
    const workflow = portfolioWorkflow.readWorkflow(workspace.id);
    return {
      id: workspace.id,
      name: workspace.name,
      isActive: workspace.id === tabs.activeWorkspaceId,
      portfolioName: workflow.portfolioName,
      isProcessing: workspace.terminal.isProcessing,
      hasPendingApproval: workspace.terminal.pendingApproval !== null,
    };
  });

  if (activeView === 'settings') {
    return (
      <div className="h-screen w-screen bg-term-bg text-term-text">
        <React.Suspense fallback={<div className="flex h-full items-start p-6 text-sm text-term-text-muted">Loading settings...</div>}>
          <SettingsErrorBoundary>
            <SettingsPage
              status={agentStatus}
              onRefreshStatus={refreshAgentStatus}
              onStatusChange={handleAgentStatusChange}
              onBackToTerminal={handleReturnToTerminal}
              workspacePreferences={workspacePreferences.preferences}
              onWorkspacePreferencesChange={workspacePreferences.updatePreferences}
            />
          </SettingsErrorBoundary>
        </React.Suspense>

        <ConfirmDialog
          isOpen={activePendingApproval !== null}
          title={activePendingApproval?.title ?? 'Approve command'}
          message={activePendingApproval?.message ?? ''}
          confirmLabel="Approve"
          cancelLabel="Deny"
          variant="warning"
          onConfirm={() => resolvePendingAgentApproval(tabs.activeWorkspaceId, true)}
          onCancel={() => resolvePendingAgentApproval(tabs.activeWorkspaceId, false)}
        />
      </div>
    );
  }

  return (
    <div className="flex h-screen bg-term-bg text-term-text">
      {activeView === 'terminal' && (
        <Sidebar
          activeView={activeView}
          isOpen={sidebarOpen}
          onOpenResearch={() => {
            handleOpenResearch();
          }}
          onOpenTerminal={() => setActiveView('terminal')}
          onOpenSettings={() => {
            void handleOpenSettings();
          }}
          onToggle={() => setSidebarOpen((prev) => !prev)}
          onCommand={(command) => {
            void handleCommand(tabs.activeWorkspaceId, command);
          }}
          portfolio={activePortfolioWorkflow.portfolioSnapshot}
          tickerHistory={tickerHistory.history}
          isTickerHistoryLoaded={tickerHistory.isLoaded}
          chatHistory={chatHistory.history}
          isChatHistoryLoaded={chatHistory.isLoaded}
          onChatHistoryClick={handleRestoreChatHistory}
          onRemoveChatHistoryEntry={chatHistory.removeChat}
        />
      )}

      <div
        className={`flex-1 ${sidebarOpen ? 'ml-0' : ''} transition-all flex min-h-0 min-w-0 flex-col`}
      >
        {activeView === 'terminal' ? (
          <TabBar
            tabs={tabBarTabs}
            onTabClick={(id) => {
              setActiveView('terminal');
              tabs.setActiveWorkspace(id);
            }}
            onTabClose={handleCloseWorkspace}
            onNewTab={handleCreateWorkspace}
            onTabRename={(id, name) => tabs.renameWorkspace(id, name)}
          />
        ) : null}

        {activeView === 'research' ? (
          <React.Suspense fallback={<div className="flex-1 p-6 text-sm text-term-text-muted">Loading research workspace...</div>}>
            <ResearchScreen
              navigationIntent={researchIntent}
              onConsumeNavigationIntent={() => setResearchIntent(null)}
              onOpenTerminal={handleReturnToTerminal}
              onOpenSettings={handleOpenSettings}
            />
          </React.Suspense>
        ) : (
          <Terminal
            workspaceId={tabs.activeWorkspaceId}
            history={activeTerminalState?.history ?? []}
            inputDraft={activeTerminalState?.inputDraft ?? ''}
            isProcessing={activeTerminalState?.isProcessing ?? false}
            inputRef={commandInputRef}
            onSubmit={(command) => {
              void handleCommand(tabs.activeWorkspaceId, command);
            }}
            onInputDraftChange={(value) =>
              tabs.setWorkspaceInputDraft(tabs.activeWorkspaceId, value)
            }
            onRunCommand={(command) => runCommand(tabs.activeWorkspaceId, command)}
            onStartPortfolioAction={handleStartPortfolioAction}
            onUpdatePortfolioDraft={handleUpdatePortfolioDraft}
            onClearPortfolioAction={handleClearPortfolioAction}
            resetCommandIndex={resetCommandIndex}
            portfolioWorkflow={activePortfolioWorkflow}
            scrollTop={activeTerminalState?.scrollTop ?? 0}
            stickToBottom={activeTerminalState?.stickToBottom ?? true}
            collapsedThinkingEntryIds={activeTerminalState?.collapsedThinkingEntryIds ?? []}
            onScrollStateChange={tabs.setWorkspaceScrollState}
            onToggleThinkingEntry={tabs.toggleWorkspaceThinkingCollapse}
          />
        )}
      </div>

      <ConfirmDialog
        isOpen={activePendingApproval !== null}
        title={activePendingApproval?.title ?? 'Approve command'}
        message={activePendingApproval?.message ?? ''}
        confirmLabel="Approve"
        cancelLabel="Deny"
        variant="warning"
        onConfirm={() => resolvePendingAgentApproval(tabs.activeWorkspaceId, true)}
        onCancel={() => resolvePendingAgentApproval(tabs.activeWorkspaceId, false)}
      />
    </div>
  );
}

export default App;
