import React, { Suspense, useDeferredValue, useEffect, useMemo, useState } from 'react';
import { Plus } from 'lucide-react';
import { researchBridge } from '../../lib/researchBridge';
import {
  type ResearchComposerState,
  useResearchGhosts,
  useResearchKeyboard,
  useResearchLayoutPrefs,
  useResearchProjection,
  useResearchSelection,
  useResearchWorkspace,
} from '../../hooks';
import type {
  NoteCaptureResult,
  NoteAuditTrail,
  ResearchFilters,
  ResearchNavigationIntent,
  ResearchWorkspace,
} from '../../types/research';
import { CreateWorkspaceModal } from './CreateWorkspaceModal';
import { ResearchCaptureModal } from './ResearchCaptureModal';
import { ResearchInspector } from './ResearchInspector';
import { ResearchShell } from './ResearchShell';
import { ResearchSidebar } from './ResearchSidebar';
import { ResearchToolbar } from './ResearchToolbar';
import { CatalystRiskMap } from './views/CatalystRiskMap';
import { EvidenceTracePanel } from './views/EvidenceTracePanel';
import { MemoWorkbench } from './views/MemoWorkbench';
import { ResearchCanvas } from './views/ResearchCanvas';
import { ResearchKanban } from './views/ResearchKanban';
import { ResearchTimeline } from './views/ResearchTimeline';
import { ThesisBoard } from './views/ThesisBoard';

const ResearchGraph = React.lazy(() =>
  import('./views/ResearchGraph').then((module) => ({ default: module.ResearchGraph })),
);

interface ResearchModeProps {
  workspaces: ResearchWorkspace[];
  activeWorkspaceId: string | null;
  navigationIntent?: ResearchNavigationIntent | null;
  onSelectWorkspace: (workspaceId: string) => void;
  onEnsureWorkspace: (request: {
    ticker?: string;
    workspaceId?: string | null;
  }) => Promise<ResearchWorkspace | null>;
  onCaptureResearchNote: (args: {
    draft: ResearchComposerState;
    fallbackTicker?: string;
    explicitWorkspaceId?: string | null;
    autoCreateFromTicker?: boolean;
  }) => Promise<NoteCaptureResult>;
  onConsumeNavigationIntent: () => void;
  onOpenTerminal?: () => void;
  onOpenSettings?: () => void;
  isSidebarOpen?: boolean;
  onToggleSidebar?: () => void;
  activeView?: 'terminal' | 'research' | 'settings';
}

const emptyFilters: ResearchFilters = {
  search: '',
  noteTypes: [],
  evidenceStatuses: [],
  showArchived: false,
  showGhosts: true,
};

const memoStorageKey = (workspaceId: string) => `mosaiciq.research.memo.${workspaceId}`;

export const ResearchMode: React.FC<ResearchModeProps> = ({
  workspaces,
  activeWorkspaceId,
  navigationIntent,
  onSelectWorkspace,
  onEnsureWorkspace,
  onCaptureResearchNote,
  onConsumeNavigationIntent,
  onOpenTerminal,
  onOpenSettings,
  isSidebarOpen = true,
  onToggleSidebar = () => {},
  activeView,
}) => {
  const workspaceState = useResearchWorkspace({
    workspaceId: activeWorkspaceId,
    initialView: navigationIntent?.preferredView,
  });
  const projectionState = useResearchProjection(activeWorkspaceId, workspaceState.selectedView);
  const selection = useResearchSelection();
  const { prefs, setDensity, toggleInspector, toggleMemoPreview } = useResearchLayoutPrefs();
  const [filters, setFilters] = useState<ResearchFilters>(emptyFilters);
  const deferredSearch = useDeferredValue(filters.search);
  const [memoDraft, setMemoDraft] = useState('');
  const [auditTrail, setAuditTrail] = useState<NoteAuditTrail | null>(null);
  const [isLoadingAuditTrail, setIsLoadingAuditTrail] = useState(false);
  const [isCaptureModalOpen, setIsCaptureModalOpen] = useState(false);
  const [isCreateWorkspaceModalOpen, setIsCreateWorkspaceModalOpen] = useState(false);
  const [terminalNoteSeed, setTerminalNoteSeed] = useState<Pick<
    ResearchComposerState,
    'rawText' | 'ticker'
  > & {
    contextLabel?: string;
  } | null>(null);

  useEffect(() => {
    if (!activeWorkspaceId) {
      setMemoDraft('');
      return;
    }

    const stored = localStorage.getItem(memoStorageKey(activeWorkspaceId));
    setMemoDraft(stored ?? '');
  }, [activeWorkspaceId]);

  useEffect(() => {
    if (!activeWorkspaceId) {
      return;
    }
    localStorage.setItem(memoStorageKey(activeWorkspaceId), memoDraft);
  }, [activeWorkspaceId, memoDraft]);

  useEffect(() => {
    if (!navigationIntent) {
      return;
    }

    if (!activeWorkspaceId && navigationIntent.ticker) {
      void onEnsureWorkspace({ ticker: navigationIntent.ticker }).then((workspace) => {
        if (workspace) {
          onSelectWorkspace(workspace.id);
        }
      });
    }

    if (navigationIntent.preferredView) {
      workspaceState.setView(navigationIntent.preferredView);
    }

    // Open capture modal if terminal note seed is provided
    if (navigationIntent.terminalNoteSeed) {
      setTerminalNoteSeed({
        rawText: navigationIntent.terminalNoteSeed.rawText ?? '',
        ticker: navigationIntent.terminalNoteSeed.ticker ?? '',
        contextLabel: navigationIntent.terminalNoteSeed.contextLabel,
      });
      setIsCaptureModalOpen(true);
    }

    onConsumeNavigationIntent();
  }, [
    activeWorkspaceId,
    navigationIntent,
    onConsumeNavigationIntent,
    onEnsureWorkspace,
    onSelectWorkspace,
    workspaceState,
  ]);

  const projection = projectionState.projection;
  const selectedWorkspaceRecord = useMemo(
    () => workspaces.find((workspace) => workspace.id === activeWorkspaceId) ?? null,
    [activeWorkspaceId, workspaces],
  );
  const currentWorkspace =
    (projection?.workspace.id === activeWorkspaceId ? projection.workspace : null) ??
    (workspaceState.workspace?.id === activeWorkspaceId ? workspaceState.workspace : null) ??
    selectedWorkspaceRecord;

  const filteredNotes = useMemo(() => {
    const notes = projection?.notes ?? [];
    return notes.filter((note) => {
      if (!filters.showArchived && note.archived) {
        return false;
      }
      if (
        deferredSearch &&
        !`${note.title ?? ''} ${note.cleanedText} ${note.aiAnnotation ?? ''}`
          .toLowerCase()
          .includes(deferredSearch.toLowerCase())
      ) {
        return false;
      }
      if (filters.noteTypes.length > 0 && !filters.noteTypes.includes(note.noteType)) {
        return false;
      }
      if (
        filters.evidenceStatuses.length > 0 &&
        !filters.evidenceStatuses.includes(note.evidenceStatus)
      ) {
        return false;
      }
      return true;
    });
  }, [deferredSearch, filters.evidenceStatuses, filters.noteTypes, filters.showArchived, projection?.notes]);

  const filteredGhosts = useMemo(() => {
    if (!filters.showGhosts) {
      return [];
    }
    return projection?.ghosts ?? [];
  }, [filters.showGhosts, projection?.ghosts]);

  const { visibleGhosts, railGhosts } = useResearchGhosts(filteredGhosts);

  const selectedNote = filteredNotes.find((note) => selection.selectedNoteIds.includes(note.id)) ?? null;
  const selectedGhost = filteredGhosts.find((ghost) => ghost.id === selection.selectedGhostId) ?? null;

  const refreshAuditTrail = React.useCallback(async (noteId: string) => {
    setIsLoadingAuditTrail(true);
    try {
      const trail = await researchBridge.getNoteAuditTrail({ noteId });
      setAuditTrail(trail);
    } finally {
      setIsLoadingAuditTrail(false);
    }
  }, []);

  useEffect(() => {
    if (!selectedNote) {
      setAuditTrail(null);
      setIsLoadingAuditTrail(false);
      return;
    }

    let cancelled = false;
    setIsLoadingAuditTrail(true);
    void researchBridge
      .getNoteAuditTrail({ noteId: selectedNote.id })
      .then((trail) => {
        if (!cancelled) {
          setAuditTrail(trail);
        }
      })
      .finally(() => {
        if (!cancelled) {
          setIsLoadingAuditTrail(false);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [selectedNote]);

  useResearchKeyboard({
    enabled: Boolean(activeWorkspaceId),
    onFocusCapture: () => {
      setIsCaptureModalOpen(true);
    },
    onOpenSearch: () => {
      const element = document.getElementById('research-sidebar-search');
      if (element instanceof HTMLElement) {
        element.focus();
      }
    },
    onOpenMemo: () => workspaceState.setView('memo_drafting'),
    onOpenTerminal: onOpenTerminal,
    onArchiveSelection: () => {
      if (selectedNote) {
        void workspaceState.archiveNote(selectedNote.id, !selectedNote.archived);
      }
    },
    onPinSelection: () => {
      if (selectedNote) {
        void workspaceState.updateNote({
          noteId: selectedNote.id,
          pinned: !selectedNote.pinned,
        });
      }
    },
    onSelectView: workspaceState.setView,
    onCycleGhost: (direction) => {
      if (visibleGhosts.length === 0) {
        return;
      }
      const currentIndex = visibleGhosts.findIndex((ghost) => ghost.id === selection.selectedGhostId);
      const nextIndex =
        currentIndex === -1
          ? 0
          : (currentIndex + direction + visibleGhosts.length) % visibleGhosts.length;
      selection.selectGhost(visibleGhosts[nextIndex].id);
    },
  });

  const handleCreateWorkspace = async () => {
    setIsCreateWorkspaceModalOpen(true);
  };

  const handleCreateWorkspaceSubmit = async (ticker: string) => {
    const workspace = await onEnsureWorkspace({ ticker });
    if (workspace) {
      onSelectWorkspace(workspace.id);
    }
  };

  const renderView = () => {
    switch (workspaceState.selectedView) {
      case 'canvas':
        return (
          <ResearchCanvas
            notes={filteredNotes}
            ghosts={railGhosts}
            density={prefs.density}
            selectedNoteIds={selection.selectedNoteIds}
            selectedGhostId={selection.selectedGhostId}
            onSelectNote={selection.selectNote}
            onSelectGhost={selection.selectGhost}
          />
        );
      case 'kanban':
        return (
          <ResearchKanban
            columns={projection?.kanbanColumns ?? []}
            density={prefs.density}
            selectedNoteIds={selection.selectedNoteIds}
            onSelectNote={selection.selectNote}
          />
        );
      case 'graph':
        return (
          <Suspense fallback={<div className="text-sm text-term-text-muted">Loading graph...</div>}>
            <ResearchGraph
              nodes={projection?.graphNodes ?? []}
              edges={projection?.graphEdges ?? []}
              selectedNodeId={selection.selectedNoteIds[0]}
              onSelectNode={selection.selectNote}
            />
          </Suspense>
        );
      case 'thesis_builder':
        return (
          <ThesisBoard
            notes={filteredNotes}
            ghosts={visibleGhosts}
            density={prefs.density}
            selectedNoteIds={selection.selectedNoteIds}
            selectedGhostId={selection.selectedGhostId}
            onSelectNote={selection.selectNote}
            onSelectGhost={selection.selectGhost}
          />
        );
      case 'memo_drafting':
        return (
          <MemoWorkbench
            memoBlocks={projection?.memoBlocks ?? []}
            notes={filteredNotes.filter((note) =>
              ['quoted', 'corroborated', 'inferred'].includes(note.evidenceStatus),
            )}
            value={memoDraft}
            showPreview={prefs.memoPreview}
            onChange={setMemoDraft}
            onTogglePreview={toggleMemoPreview}
            onInsert={(kind) => {
              const prefix =
                kind === 'heading'
                  ? '\n## '
                  : kind === 'bullet'
                    ? '\n- '
                    : kind === 'quote'
                      ? '\n> '
                      : '\n> Thesis angle: ';
              setMemoDraft((current) => `${current}${prefix}`);
            }}
          />
        );
      case 'evidence_trace':
        return <EvidenceTracePanel auditTrail={auditTrail} />;
      case 'catalyst_risk_map':
        return (
          <CatalystRiskMap
            notes={filteredNotes}
            ghosts={visibleGhosts}
            density={prefs.density}
            selectedNoteIds={selection.selectedNoteIds}
            onSelectNote={selection.selectNote}
            onSelectGhost={selection.selectGhost}
          />
        );
      case 'timeline':
        return (
          <ResearchTimeline
            events={projection?.timelineEvents ?? []}
            notes={filteredNotes}
            onSelectNote={selection.selectNote}
          />
        );
      default:
        return null;
    }
  };

  return (
    <div className="flex h-full min-h-0 flex-col bg-[var(--research-bg)]">
      <ResearchShell
        sidebar={
          <ResearchSidebar
            workspaces={workspaces}
            activeWorkspaceId={activeWorkspaceId}
            activeView={workspaceState.selectedView}
            filters={filters}
            onOpenTerminal={onOpenTerminal}
            onOpenSettings={onOpenSettings}
            activeAppView={activeView}
            onCreateWorkspace={() => {
              void handleCreateWorkspace();
            }}
            isOpen={isSidebarOpen}
            onToggle={onToggleSidebar}
            onSelectWorkspace={onSelectWorkspace}
            onSelectView={workspaceState.setView}
            onFilterChange={(patch) => setFilters((current) => ({ ...current, ...patch }))}
          />
        }
        toolbar={
          <ResearchToolbar
            workspace={currentWorkspace}
            visibleGhostCount={visibleGhosts.length}
            activeJobCount={
              Object.values(projectionState.jobs).filter(
                (job) => job.status === 'queued' || job.status === 'running',
              ).length
            }
            density={prefs.density}
            onDensityChange={setDensity}
            onToggleInspector={toggleInspector}
            jobs={Object.values(projectionState.jobs)}
            extraActions={
              <button
                type="button"
                onClick={() => setIsCaptureModalOpen(true)}
                className="flex items-center gap-1.5 rounded bg-info px-3 py-1.5 text-xs font-mono font-semibold text-term-bg transition-colors hover:brightness-110"
              >
                <Plus className="w-3.5 h-3.5" />
                New Note
              </button>
            }
          />
        }
        onOpenTerminal={onOpenTerminal}
        onOpenSettings={onOpenSettings}
        isSidebarOpen={isSidebarOpen}
        onToggleSidebar={onToggleSidebar}
        activeView={activeView}
        inspector={
          prefs.showInspector ? (
            <ResearchInspector
              note={selectedNote}
              ghost={selectedGhost}
              auditTrail={auditTrail}
              isLoadingAuditTrail={isLoadingAuditTrail}
              onRefreshAuditTrail={() => {
                if (selectedNote) {
                  void refreshAuditTrail(selectedNote.id);
                }
              }}
              onUpdateNote={(noteId, patch) => workspaceState.updateNote({ noteId, ...patch })}
              onArchiveNote={(noteId, archived) => workspaceState.archiveNote(noteId, archived)}
              onPromoteNote={(noteId, thesisStatus, noteType) =>
                workspaceState.promoteNoteToThesis(noteId, thesisStatus, noteType)
              }
              onReviewGhost={(ghostId, action) => workspaceState.reviewGhost(ghostId, action)}
            />
          ) : null
        }
      >
        {!activeWorkspaceId ? (
          <div className="rounded-[28px] border border-dashed border-term-border-focus/60 bg-term-surface p-10 text-center">
            <h2 className="text-xl font-semibold text-term-text">No research workspace selected</h2>
            <p className="mt-3 text-sm leading-7 text-term-text-muted">
              Create a workspace from the terminal capture bar or start one directly here to begin organizing research.
            </p>
          </div>
        ) : projectionState.isLoading ? (
          <div className="rounded-[28px] border border-term-border bg-term-surface p-10 text-sm text-term-text-muted">
            Loading workspace projection...
          </div>
        ) : projectionState.error ? (
          <div className="rounded-[28px] border border-negative/40 bg-negative/10 p-10 text-sm text-negative">
            {projectionState.error}
          </div>
        ) : (
          renderView()
        )}
      </ResearchShell>

      {/* Capture Modal */}
      <ResearchCaptureModal
        isOpen={isCaptureModalOpen}
        onClose={() => {
          setIsCaptureModalOpen(false);
          setTerminalNoteSeed(null);
        }}
        workspaces={workspaces}
        defaultWorkspaceId={activeWorkspaceId}
        defaultTicker={currentWorkspace?.primaryTicker ?? navigationIntent?.ticker}
        defaultRawText={terminalNoteSeed?.rawText}
        contextLabel={
          terminalNoteSeed?.contextLabel ??
          (currentWorkspace ? `${currentWorkspace.primaryTicker} workspace` : 'Quick capture')
        }
        onWorkspaceChange={onSelectWorkspace}
        onSubmitCapture={(draft) =>
          onCaptureResearchNote({
            draft,
            fallbackTicker: currentWorkspace?.primaryTicker ?? navigationIntent?.ticker,
            explicitWorkspaceId: activeWorkspaceId,
            autoCreateFromTicker: Boolean(
              currentWorkspace?.primaryTicker ?? navigationIntent?.ticker,
            ),
          })
        }
        onCaptured={(note) => {
          onSelectWorkspace(note.workspaceId);
          selection.selectNote(note.id);
        }}
      />

      {/* Create Workspace Modal */}
      <CreateWorkspaceModal
        isOpen={isCreateWorkspaceModalOpen}
        onClose={() => setIsCreateWorkspaceModalOpen(false)}
        onCreateWorkspace={handleCreateWorkspaceSubmit}
        defaultTicker={navigationIntent?.ticker}
      />
    </div>
  );
};
