import React, { Suspense, useDeferredValue, useEffect, useMemo, useState } from '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 { ResearchCaptureBar } from './ResearchCaptureBar';
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;
}

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,
}) => {
  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);

  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);
    }
    onConsumeNavigationIntent();
  }, [
    activeWorkspaceId,
    navigationIntent,
    onConsumeNavigationIntent,
    onEnsureWorkspace,
    onSelectWorkspace,
    workspaceState,
  ]);

  const projection = projectionState.projection;

  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;

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

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

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

  useResearchKeyboard({
    enabled: Boolean(activeWorkspaceId),
    onFocusCapture: () => {
      const element = document.getElementById('research-capture-input');
      if (element instanceof HTMLElement) {
        element.focus();
      }
    },
    onOpenSearch: () => {
      const element = document.getElementById('research-sidebar-search');
      if (element instanceof HTMLElement) {
        element.focus();
      }
    },
    onOpenMemo: () => workspaceState.setView('memo_drafting'),
    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 () => {
    const ticker = navigationIntent?.ticker ?? window.prompt('Primary ticker for new research workspace?') ?? '';
    const trimmedTicker = ticker.trim().toUpperCase();
    if (!trimmedTicker) {
      return;
    }
    const workspace = await onEnsureWorkspace({ ticker: trimmedTicker });
    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-[#7d8fa6]">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)]">
      <div className="border-b border-[#1d2430] px-5 py-4">
        <ResearchCaptureBar
          workspaces={workspaces}
          defaultWorkspaceId={activeWorkspaceId}
          defaultTicker={workspaceState.workspace?.primaryTicker ?? navigationIntent?.ticker}
          contextLabel={workspaceState.workspace ? `${workspaceState.workspace.primaryTicker} workspace` : 'Quick capture'}
          onWorkspaceChange={onSelectWorkspace}
          onEnsureWorkspace={onEnsureWorkspace}
          onSubmitCapture={(draft) =>
            onCaptureResearchNote({
              draft,
              fallbackTicker: workspaceState.workspace?.primaryTicker ?? navigationIntent?.ticker,
              explicitWorkspaceId: activeWorkspaceId,
              autoCreateFromTicker: Boolean(
                workspaceState.workspace?.primaryTicker ?? navigationIntent?.ticker,
              ),
            })
          }
          onCaptured={(note) => {
            onSelectWorkspace(note.workspaceId);
            selection.selectNote(note.id);
            void projectionState.refreshProjection();
          }}
        />
      </div>
      <ResearchShell
        sidebar={
          <ResearchSidebar
            workspaces={workspaces}
            activeWorkspaceId={activeWorkspaceId}
            activeView={workspaceState.selectedView}
            filters={filters}
            onCreateWorkspace={() => {
              void handleCreateWorkspace();
            }}
            onSelectWorkspace={onSelectWorkspace}
            onSelectView={workspaceState.setView}
            onFilterChange={(patch) => setFilters((current) => ({ ...current, ...patch }))}
          />
        }
        toolbar={
          <ResearchToolbar
            workspace={workspaceState.workspace}
            visibleGhostCount={visibleGhosts.length}
            activeJobCount={Object.values(projectionState.jobs).length}
            density={prefs.density}
            onDensityChange={setDensity}
            onToggleInspector={toggleInspector}
            jobs={Object.values(projectionState.jobs)}
          />
        }
        inspector={
          prefs.showInspector ? (
            <ResearchInspector
              note={selectedNote}
              ghost={selectedGhost}
              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-[#2c3950] bg-[#10151d] p-10 text-center">
            <h2 className="text-xl font-semibold text-[#eef4ff]">No research workspace selected</h2>
            <p className="mt-3 text-sm leading-7 text-[#8ea6c0]">
              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-[#1d2430] bg-[#10151d] p-10 text-sm text-[#8ea6c0]">
            Loading workspace projection...
          </div>
        ) : projectionState.error ? (
          <div className="rounded-[28px] border border-[#4a2930] bg-[#1d1014] p-10 text-sm text-[#ffb6c0]">
            {projectionState.error}
          </div>
        ) : (
          renderView()
        )}
      </ResearchShell>
    </div>
  );
};
