import type { PipelineJob, ResearchFilters, ResearchNote, WorkspaceProjection } from '../types/research';

export interface ResearchWorkspaceSnapshotViewModel {
  workspaceId: string;
  workspaceName: string;
  primaryTicker: string;
  noteCount: number;
  archivedNoteCount: number;
  pinnedNoteCount: number;
  ghostCount: number;
  visibleGhostCount: number;
  hiddenGhostCount: number;
  activeJobCount: number;
}

const isVisibleGhostState = (visibilityState: string) =>
  visibilityState === 'visible' || visibilityState === 'pinned' || visibilityState === 'collapsed';

export const buildResearchWorkspaceSnapshotViewModel = (
  snapshot: WorkspaceProjection | null,
  jobs: PipelineJob[] = [],
): ResearchWorkspaceSnapshotViewModel | null => {
  if (!snapshot) {
    return null;
  }

  const visibleGhostCount = snapshot.ghosts.filter((ghost) =>
    isVisibleGhostState(ghost.visibilityState),
  ).length;

  return {
    workspaceId: snapshot.workspace.id,
    workspaceName: snapshot.workspace.name,
    primaryTicker: snapshot.workspace.primaryTicker,
    noteCount: snapshot.notes.length,
    archivedNoteCount: snapshot.notes.filter((note) => note.archived).length,
    pinnedNoteCount: snapshot.notes.filter((note) => note.pinned).length,
    ghostCount: snapshot.ghosts.length,
    visibleGhostCount,
    hiddenGhostCount: Math.max(snapshot.ghosts.length - visibleGhostCount, 0),
    activeJobCount: jobs.filter(
      (job) => job.status === 'queued' || job.status === 'running',
    ).length,
  };
};

export const noteMatchesFilters = (
  note: ResearchNote,
  filters: ResearchFilters,
  searchIds: Set<string> | null,
) => {
  if (!filters.showArchived && note.archived) {
    return false;
  }

  if (searchIds && !searchIds.has(note.id)) {
    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;
};

export const filterSnapshotNotes = (
  snapshot: WorkspaceProjection | null,
  filters: ResearchFilters,
  searchIds: string[] | null,
) => {
  if (!snapshot) {
    return [];
  }

  const searchIdSet = searchIds ? new Set(searchIds) : null;
  const matchingNotes = snapshot.notes.filter((note) =>
    noteMatchesFilters(note, filters, searchIdSet),
  );
  if (!searchIds) {
    return matchingNotes;
  }

  const matchingNoteById = new Map(matchingNotes.map((note) => [note.id, note]));
  return searchIds
    .map((noteId) => matchingNoteById.get(noteId) ?? null)
    .filter((note): note is ResearchNote => note !== null);
};

export const filterSnapshotGhosts = (
  snapshot: WorkspaceProjection | null,
  filters: ResearchFilters,
) => {
  if (!snapshot || !filters.showGhosts) {
    return [];
  }

  return snapshot.ghosts;
};

export const buildVisibleLinkSet = (
  snapshot: WorkspaceProjection | null,
  visibleNotes: ResearchNote[],
) => {
  if (!snapshot) {
    return [];
  }

  const visibleNoteIds = new Set(visibleNotes.map((note) => note.id));
  return snapshot.links.filter(
    (link) => visibleNoteIds.has(link.fromNoteId) && visibleNoteIds.has(link.toNoteId),
  );
};

export const isSelectedNoteHidden = (
  selectedNote: ResearchNote | null,
  visibleNotes: ResearchNote[],
) => Boolean(selectedNote && !visibleNotes.some((note) => note.id === selectedNote.id));

export const isSelectedGhostHidden = (
  selectedGhostId: string | null,
  visibleGhostIds: string[],
) => Boolean(selectedGhostId && !visibleGhostIds.includes(selectedGhostId));
