import React, { useCallback, useDeferredValue, useEffect, useMemo, useState } from 'react';
import { useResearchGhosts, useResearchKeyboard } from '../../hooks';
import { rebuildWorkspaceProjection } from '../../lib/researchProjection';
import { ResearchEventSync } from '../../research/ResearchEventSync';
import {
  researchActionKeys,
  useResearchActions,
} from '../../research/researchActions';
import { isResearchIntentEmpty } from '../../research/researchApi';
import {
  useResearchAuditTrailQuery,
  useResearchFilesQuery,
  useResearchJobsQuery,
  useResearchSearchIdsQuery,
  useResearchSnapshotQuery,
  useResearchWorkspacesQuery,
} from '../../research/researchQueries';
import {
  buildResearchWorkspaceSnapshotViewModel,
  buildVisibleLinkSet,
  filterSnapshotGhosts,
  filterSnapshotNotes,
  isSelectedGhostHidden,
  isSelectedNoteHidden,
} from '../../research/researchSelectors';
import {
  defaultResearchFilters,
  getMutationStatus,
  getWorkspaceSelection,
  useResearchUiStore,
} from '../../research/researchUiStore';
import type { ResearchComposerState } from '../../hooks/useResearchComposer';
import type {
  ResearchFile,
  ResearchNavigationIntent,
  UploadResearchFileInput,
} from '../../types/research';
import { CreateWorkspaceModalController } from './CreateWorkspaceModalController';
import { ResearchCaptureModalController } from './ResearchCaptureModalController';
import { ResearchHeader } from './ResearchHeader';
import { ResearchInspectorPane } from './ResearchInspectorPane';
import { ResearchShell } from './ResearchShell';
import { ResearchWorkbench } from './ResearchWorkbench';
import { ResearchWorkspaceRail } from './ResearchWorkspaceRail';
import {
  buildLinkedNoteCountByFileId,
  openResearchFile,
  ResearchFilePreviewModal,
} from './primitives/ResearchFiles';
import type { WorkspaceViewKind } from '../../types/research';

interface ResearchScreenProps {
  navigationIntent?: ResearchNavigationIntent | null;
  onConsumeNavigationIntent: () => void;
  onOpenTerminal?: () => void;
  onOpenSettings?: () => void;
}

const openInspectorOnMobile = () => {
  if (typeof window === 'undefined') {
    return false;
  }

  return window.innerWidth < 1024;
};

export const ResearchScreen: React.FC<ResearchScreenProps> = ({
  navigationIntent,
  onConsumeNavigationIntent,
  onOpenTerminal,
  onOpenSettings,
}) => {
  const actions = useResearchActions();
  const [previewFile, setPreviewFile] = useState<ResearchFile | null>(null);
  const activeWorkspaceId = useResearchUiStore((state) => state.activeWorkspaceId);
  const viewByWorkspaceId = useResearchUiStore((state) => state.viewByWorkspaceId);
  const filtersByWorkspaceId = useResearchUiStore((state) => state.filtersByWorkspaceId);
  const memoDraftByWorkspaceId = useResearchUiStore(
    (state) => state.memoDraftByWorkspaceId,
  );
  const density = useResearchUiStore((state) => state.density);
  const sidebarCollapsed = useResearchUiStore((state) => state.sidebarCollapsed);
  const inspectorPinned = useResearchUiStore((state) => state.inspectorPinned);
  const memoPreview = useResearchUiStore((state) => state.memoPreview);
  const selectionByWorkspaceId = useResearchUiStore(
    (state) => state.selectionByWorkspaceId,
  );
  const mobilePane = useResearchUiStore((state) => state.mobilePane);
  const lastNavigationIntentToken = useResearchUiStore(
    (state) => state.lastNavigationIntentToken,
  );
  const mutationStateByKey = useResearchUiStore((state) => state.mutationStateByKey);
  const initializeWorkspaceState = useResearchUiStore(
    (state) => state.initializeWorkspaceState,
  );
  const setDensity = useResearchUiStore((state) => state.setDensity);
  const toggleSidebarCollapsed = useResearchUiStore(
    (state) => state.toggleSidebarCollapsed,
  );
  const toggleInspectorPinned = useResearchUiStore(
    (state) => state.toggleInspectorPinned,
  );
  const toggleMemoPreview = useResearchUiStore((state) => state.toggleMemoPreview);
  const openCaptureModal = useResearchUiStore((state) => state.openCaptureModal);
  const openCreateWorkspaceModal = useResearchUiStore(
    (state) => state.openCreateWorkspaceModal,
  );
  const setMobilePane = useResearchUiStore((state) => state.setMobilePane);
  const setLastNavigationIntentToken = useResearchUiStore(
    (state) => state.setLastNavigationIntentToken,
  );

  const { data: workspaces = [], isLoading: isLoadingWorkspaces } =
    useResearchWorkspacesQuery();

  useEffect(() => {
    if (isLoadingWorkspaces) {
      return;
    }

    if (!workspaces.length) {
      if (activeWorkspaceId) {
        useResearchUiStore.getState().setActiveWorkspaceId(null);
      }
      return;
    }

    if (activeWorkspaceId && workspaces.some((workspace) => workspace.id === activeWorkspaceId)) {
      return;
    }

    actions.selectWorkspace(workspaces[0].id);
  }, [activeWorkspaceId, actions, isLoadingWorkspaces, workspaces]);

  const activeWorkspace =
    workspaces.find((workspace) => workspace.id === activeWorkspaceId) ?? null;
  const snapshotQuery = useResearchSnapshotQuery(activeWorkspaceId);
  const snapshot = snapshotQuery.data ?? null;

  useEffect(() => {
    if (!snapshot?.workspace) {
      return;
    }

    initializeWorkspaceState(snapshot.workspace.id, snapshot.workspace.defaultView);
  }, [initializeWorkspaceState, snapshot?.workspace.defaultView, snapshot?.workspace.id]);

  const filters = activeWorkspaceId
    ? filtersByWorkspaceId[activeWorkspaceId] ?? defaultResearchFilters
    : defaultResearchFilters;
  const deferredSearch = useDeferredValue(filters.search);
  const currentView: WorkspaceViewKind = activeWorkspaceId
    ? viewByWorkspaceId[activeWorkspaceId] ??
      snapshot?.workspace.defaultView ??
      activeWorkspace?.defaultView ??
      'canvas'
    : snapshot?.workspace.defaultView ?? activeWorkspace?.defaultView ?? 'canvas';
  const memoDraft = activeWorkspaceId
    ? memoDraftByWorkspaceId[activeWorkspaceId] ?? ''
    : '';
  const selection = getWorkspaceSelection(activeWorkspaceId, selectionByWorkspaceId);
  const jobsQuery = useResearchJobsQuery(activeWorkspaceId);
  const filesQuery = useResearchFilesQuery(activeWorkspaceId);
  const searchIdsQuery = useResearchSearchIdsQuery(
    activeWorkspaceId,
    deferredSearch,
    filters.showArchived,
  );

  const selectedNote =
    snapshot?.notes.find((note) => note.id === selection.noteId) ?? null;
  const selectedGhost =
    snapshot?.ghosts.find((ghost) => ghost.id === selection.ghostId) ?? null;
  const auditTrailQuery = useResearchAuditTrailQuery(selectedNote?.id ?? null);

  const visibleNotes = useMemo(
    () =>
      filterSnapshotNotes(
        snapshot,
        filters,
        deferredSearch.trim() ? searchIdsQuery.data ?? [] : null,
      ),
    [deferredSearch, filters, searchIdsQuery.data, snapshot],
  );
  const filteredGhosts = useMemo(
    () => filterSnapshotGhosts(snapshot, filters),
    [filters, snapshot],
  );
  const visibleLinks = useMemo(
    () => buildVisibleLinkSet(snapshot, visibleNotes),
    [snapshot, visibleNotes],
  );
  const visibleProjection = useMemo(
    () =>
      snapshot
        ? rebuildWorkspaceProjection(snapshot, {
            notes: visibleNotes,
            links: visibleLinks,
            ghosts: filteredGhosts,
          })
        : null,
    [filteredGhosts, snapshot, visibleLinks, visibleNotes],
  );
  const { visibleGhosts, railGhosts } = useResearchGhosts(
    visibleProjection?.ghosts ?? [],
  );

  const selectedNoteHidden = isSelectedNoteHidden(selectedNote, visibleNotes);
  const selectedGhostHidden = isSelectedGhostHidden(
    selectedGhost?.id ?? null,
    visibleGhosts.map((ghost) => ghost.id),
  );
  const hiddenMessage = selectedNoteHidden
    ? 'Selected note is hidden by current filters.'
    : selectedGhostHidden
      ? 'Selected ghost is hidden by current filters.'
      : null;

  const viewModel = useMemo(
    () => buildResearchWorkspaceSnapshotViewModel(snapshot, jobsQuery.data ?? []),
    [jobsQuery.data, snapshot],
  );
  const workspaceFiles = useMemo(
    () => filesQuery.data ?? [],
    [filesQuery.data],
  );
  const linkedNoteCountByFileId = useMemo(
    () => buildLinkedNoteCountByFileId(snapshot?.notes ?? []),
    [snapshot?.notes],
  );
  const hasActiveFilters = Boolean(
    deferredSearch.trim() ||
      filters.noteTypes.length > 0 ||
      filters.evidenceStatuses.length > 0 ||
      filters.showArchived ||
      !filters.showGhosts,
  );
  const emptyMessage = hasActiveFilters
    ? 'Search or display filters may be hiding saved research items.'
    : 'Capture a note to start building this workspace.';

  const handleSelectNote = useCallback(
    (noteId: string) => {
      if (!activeWorkspaceId) {
        return;
      }
      actions.selectNote(activeWorkspaceId, noteId);
      if (openInspectorOnMobile()) {
        setMobilePane('inspector');
      }
    },
    [activeWorkspaceId, actions, setMobilePane],
  );

  const handleSelectGhost = useCallback(
    (ghostId: string) => {
      if (!activeWorkspaceId) {
        return;
      }
      actions.selectGhost(activeWorkspaceId, ghostId);
      if (openInspectorOnMobile()) {
        setMobilePane('inspector');
      }
    },
    [activeWorkspaceId, actions, setMobilePane],
  );

  const handleOpenCapture = useCallback(() => {
    openCaptureModal({
      draft: {
        workspaceId: activeWorkspaceId ?? '',
        ticker:
          snapshot?.workspace.primaryTicker ??
          activeWorkspace?.primaryTicker ??
          '',
      } satisfies Partial<ResearchComposerState>,
      contextLabel:
        snapshot?.workspace.primaryTicker || activeWorkspace?.primaryTicker
          ? `${snapshot?.workspace.primaryTicker ?? activeWorkspace?.primaryTicker} workspace`
          : 'Quick capture',
    });
  }, [activeWorkspace, activeWorkspaceId, openCaptureModal, snapshot?.workspace.primaryTicker]);

  const handleOpenLinkCapture = useCallback(() => {
    openCaptureModal({
      draft: {
        workspaceId: activeWorkspaceId ?? '',
        ticker:
          snapshot?.workspace.primaryTicker ??
          activeWorkspace?.primaryTicker ??
          '',
        captureMode: 'link',
        sourceKind: 'article',
      } satisfies Partial<ResearchComposerState>,
      contextLabel:
        snapshot?.workspace.primaryTicker || activeWorkspace?.primaryTicker
          ? `${snapshot?.workspace.primaryTicker ?? activeWorkspace?.primaryTicker} workspace`
          : 'Link capture',
    });
  }, [activeWorkspace, activeWorkspaceId, openCaptureModal, snapshot?.workspace.primaryTicker]);

  const handleUploadFiles = useCallback(
    (files: UploadResearchFileInput[]) => {
      if (!activeWorkspaceId) {
        return Promise.reject(new Error('No active research workspace.'));
      }
      return actions.uploadFiles(activeWorkspaceId, files);
    },
    [actions, activeWorkspaceId],
  );

  const handleOpenFile = useCallback((file: ResearchFile) => openResearchFile(file), []);

  useResearchKeyboard({
    enabled: Boolean(activeWorkspaceId),
    onFocusCapture: handleOpenCapture,
    onOpenSearch: () => {
      const element = document.getElementById('research-sidebar-search');
      if (element instanceof HTMLElement) {
        element.focus();
      }
    },
    onOpenMemo: () => {
      if (activeWorkspaceId) {
        actions.setView(activeWorkspaceId, 'memo_drafting');
      }
    },
    onOpenTerminal,
    onArchiveSelection: () => {
      if (selectedNote && activeWorkspaceId) {
        void actions.archiveNote(
          selectedNote.id,
          activeWorkspaceId,
          !selectedNote.archived,
        );
      }
    },
    onPinSelection: () => {
      if (selectedNote && activeWorkspaceId) {
        void actions.updateNote({
          noteId: selectedNote.id,
          workspaceId: activeWorkspaceId,
          pinned: !selectedNote.pinned,
        });
      }
    },
    onSelectView: (view) => {
      if (activeWorkspaceId) {
        actions.setView(activeWorkspaceId, view);
      }
    },
    onCycleGhost: (direction) => {
      if (!activeWorkspaceId || visibleGhosts.length === 0) {
        return;
      }

      const currentIndex = visibleGhosts.findIndex(
        (ghost) => ghost.id === selection.ghostId,
      );
      const nextIndex =
        currentIndex === -1
          ? 0
          : (currentIndex + direction + visibleGhosts.length) % visibleGhosts.length;
      actions.selectGhost(activeWorkspaceId, visibleGhosts[nextIndex].id);
    },
  });

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

    const token = JSON.stringify(navigationIntent);
    if (token === lastNavigationIntentToken) {
      return;
    }

    let cancelled = false;

    void (async () => {
      const resolvedWorkspace = await actions.ensureWorkspace({
        workspaceId: navigationIntent?.workspaceId,
        ticker: navigationIntent?.ticker,
      });
      if (cancelled) {
        return;
      }

      const resolvedWorkspaceId =
        resolvedWorkspace?.id ?? useResearchUiStore.getState().activeWorkspaceId;
      if (resolvedWorkspaceId && navigationIntent?.preferredView) {
        actions.setView(resolvedWorkspaceId, navigationIntent.preferredView);
      }

      if (navigationIntent?.terminalNoteSeed) {
        openCaptureModal({
          draft: {
            workspaceId: resolvedWorkspaceId ?? '',
            ticker:
              navigationIntent.terminalNoteSeed.ticker ??
              navigationIntent.ticker ??
              resolvedWorkspace?.primaryTicker ??
              '',
            rawText: navigationIntent.terminalNoteSeed.rawText ?? '',
          },
          seedToken: token,
          contextLabel:
            navigationIntent.terminalNoteSeed.contextLabel ??
            (resolvedWorkspace
              ? `${resolvedWorkspace.primaryTicker} workspace`
              : 'Quick capture'),
        });
      }

      setLastNavigationIntentToken(token);
      onConsumeNavigationIntent();
    })();

    return () => {
      cancelled = true;
    };
  }, [
    actions,
    lastNavigationIntentToken,
    navigationIntent,
    onConsumeNavigationIntent,
    openCaptureModal,
    setLastNavigationIntentToken,
  ]);

  const updateWorkspaceStatus = getMutationStatus(
    mutationStateByKey,
    activeWorkspaceId ? researchActionKeys.updateWorkspace(activeWorkspaceId) : '',
  );
  const archiveWorkspaceStatus = getMutationStatus(
    mutationStateByKey,
    activeWorkspaceId ? researchActionKeys.archiveWorkspace(activeWorkspaceId) : '',
  );
  const updateNoteStatus = getMutationStatus(
    mutationStateByKey,
    selectedNote ? researchActionKeys.updateNote(selectedNote.id) : '',
  );
  const archiveNoteStatus = getMutationStatus(
    mutationStateByKey,
    selectedNote ? researchActionKeys.archiveNote(selectedNote.id) : '',
  );
  const promoteNoteStatus = getMutationStatus(
    mutationStateByKey,
    selectedNote ? researchActionKeys.promoteNote(selectedNote.id) : '',
  );
  const reviewGhostStatus = getMutationStatus(
    mutationStateByKey,
    selectedGhost
      ? researchActionKeys.reviewGhost(selectedGhost.id, 'accept')
      : '',
  );

  return (
    <>
      <ResearchEventSync />
      <ResearchShell
        header={
          <ResearchHeader
            workspaces={workspaces}
            activeWorkspaceId={activeWorkspaceId}
            activeView={currentView}
            density={density}
            jobs={jobsQuery.data ?? []}
            sidebarCollapsed={sidebarCollapsed}
            inspectorPinned={inspectorPinned}
            canOpenInspector={Boolean(selectedNote || selectedGhost)}
            mobilePane={mobilePane}
            onSelectWorkspace={(workspaceId) => actions.selectWorkspace(workspaceId)}
            onSelectView={(view) => {
              if (activeWorkspaceId) {
                actions.setView(activeWorkspaceId, view);
              }
            }}
            onOpenCapture={handleOpenCapture}
            onOpenLinkCapture={handleOpenLinkCapture}
            onToggleSidebar={toggleSidebarCollapsed}
            onToggleInspector={toggleInspectorPinned}
            onSetMobilePane={setMobilePane}
            onDensityChange={setDensity}
            onOpenTerminal={onOpenTerminal}
            onOpenSettings={onOpenSettings}
          />
        }
        rail={
          <ResearchWorkspaceRail
            activeWorkspace={
              snapshot?.workspace ??
              activeWorkspace ??
              null
            }
            filters={filters}
            viewModel={viewModel}
            files={workspaceFiles}
            linkedNoteCountByFileId={linkedNoteCountByFileId}
            updateStatus={updateWorkspaceStatus}
            archiveStatus={archiveWorkspaceStatus}
            uploadStatus={
              activeWorkspaceId
                ? getMutationStatus(
                    mutationStateByKey,
                    researchActionKeys.uploadFiles(activeWorkspaceId),
                  )
                : { pending: false, error: null }
            }
            onOpenCreateWorkspace={() =>
              openCreateWorkspaceModal(snapshot?.workspace.primaryTicker ?? '')
            }
            onUpdateWorkspace={actions.updateWorkspace}
            onArchiveWorkspace={actions.archiveWorkspace}
            onUploadFiles={handleUploadFiles}
            onOpenFile={handleOpenFile}
            onPreviewFile={setPreviewFile}
            onFilterChange={(patch) => {
              if (activeWorkspaceId) {
                actions.setFilters(activeWorkspaceId, patch);
              }
            }}
            onResetFilters={() => {
              if (activeWorkspaceId) {
                actions.resetFilters(activeWorkspaceId);
              }
            }}
          />
        }
        workbench={
          <ResearchWorkbench
            projection={visibleProjection}
            currentView={currentView}
            density={density}
            selectedNoteIds={selection.noteId ? [selection.noteId] : []}
            selectedGhostId={selection.ghostId}
            visibleGhosts={visibleGhosts}
            railGhosts={railGhosts}
            memoDraft={memoDraft}
            memoPreview={memoPreview}
            auditTrail={auditTrailQuery.data ?? null}
            isLoading={snapshotQuery.isLoading || snapshotQuery.isFetching}
            error={
              snapshotQuery.error instanceof Error
                ? snapshotQuery.error.message
                : snapshotQuery.error
                  ? String(snapshotQuery.error)
                  : undefined
            }
            emptyMessage={emptyMessage}
            onSelectNote={handleSelectNote}
            onSelectGhost={handleSelectGhost}
            onMemoDraftChange={(value) => {
              if (activeWorkspaceId) {
                actions.setMemoDraft(activeWorkspaceId, value);
              }
            }}
            onToggleMemoPreview={toggleMemoPreview}
          />
        }
        inspector={
          <ResearchInspectorPane
            note={selectedNote}
            ghost={selectedGhost}
            hiddenMessage={hiddenMessage}
            auditTrail={auditTrailQuery.data ?? null}
            isLoadingAuditTrail={auditTrailQuery.isLoading || auditTrailQuery.isFetching}
            isUpdatingNote={updateNoteStatus.pending}
            isArchivingNote={archiveNoteStatus.pending}
            isPromotingNote={promoteNoteStatus.pending}
            isReviewingGhost={reviewGhostStatus.pending}
            error={
              updateNoteStatus.error ??
              archiveNoteStatus.error ??
              promoteNoteStatus.error ??
              reviewGhostStatus.error
            }
            onRefreshAuditTrail={() => {
              void auditTrailQuery.refetch();
            }}
            onUpdateNote={(noteId, patch) => {
              if (!activeWorkspaceId) {
                return Promise.reject(new Error('No active research workspace.'));
              }
              return actions.updateNote({
                noteId,
                workspaceId: activeWorkspaceId,
                ...patch,
              });
            }}
            onArchiveNote={(noteId, archived) => {
              if (!activeWorkspaceId) {
                return Promise.reject(new Error('No active research workspace.'));
              }
              return actions.archiveNote(noteId, activeWorkspaceId, archived);
            }}
            onPromoteNote={(noteId, thesisStatus, noteType) => {
              if (!activeWorkspaceId) {
                return Promise.reject(new Error('No active research workspace.'));
              }
              return actions.promoteNote(
                noteId,
                activeWorkspaceId,
                thesisStatus,
                noteType,
              );
            }}
            onReviewGhost={(ghostId, action) => {
              if (!activeWorkspaceId) {
                return Promise.reject(new Error('No active research workspace.'));
              }
              return actions.reviewGhost(ghostId, activeWorkspaceId, action);
            }}
            onResolveGhost={(ghostId, resolutionStatus, actionTaken) => {
              if (!activeWorkspaceId) {
                return Promise.reject(new Error('No active research workspace.'));
              }
              return actions.resolveGhostIntervention({
                ghostId,
                workspaceId: activeWorkspaceId,
                resolutionStatus,
                actionTaken,
              });
            }}
            onSelectNote={handleSelectNote}
            workspaceFiles={workspaceFiles}
            onUploadFiles={handleUploadFiles}
            onOpenFile={handleOpenFile}
            onPreviewFile={setPreviewFile}
          />
        }
        sidebarCollapsed={sidebarCollapsed}
        inspectorPinned={inspectorPinned}
        mobilePane={mobilePane}
        onCloseMobilePane={() => setMobilePane('none')}
      />
      <ResearchCaptureModalController />
      <ResearchFilePreviewModal file={previewFile} onClose={() => setPreviewFile(null)} />
      <CreateWorkspaceModalController />
    </>
  );
};
