import { describe, expect, it, mock } from 'bun:test';
import { QueryClient } from '@tanstack/react-query';
import {
  syncResearchGhostEvent,
  syncResearchJobEvent,
  syncResearchNoteEvent,
  syncResearchWorkspaceEvent,
} from './ResearchEventSync';
import { researchQueryKeys } from './researchQueries';
import type {
  PipelineJob,
  ResearchNote,
  ResearchWorkspace,
  WorkspaceProjection,
} from '../types/research';

const workspace: ResearchWorkspace = {
  id: 'workspace-1',
  name: 'NVDA Research',
  primaryTicker: 'NVDA',
  scope: 'single_company',
  stage: 'capture',
  defaultView: 'canvas',
  pinnedNoteIds: [],
  archived: false,
  createdAt: '2026-04-09T10:00:00Z',
  updatedAt: '2026-04-09T10:00:00Z',
};

const note: ResearchNote = {
  id: 'note-1',
  workspaceId: workspace.id,
  rawText: 'Demand is improving.',
  cleanedText: 'Demand is improving.',
  embeds: [],
  fileIds: [],
  title: 'Demand',
  noteType: 'claim',
  analystStatus: 'captured',
  confidence: 0.7,
  evidenceStatus: 'source_linked',
  inferredLinks: [],
  ghostStatus: 'none',
  thesisStatus: 'none',
  createdAt: '2026-04-09T10:00:00Z',
  updatedAt: '2026-04-09T10:00:00Z',
  provenance: {
    createdBy: 'manual',
    captureMethod: 'quick_entry',
    sourceKind: 'manual',
    createdAt: '2026-04-09T10:00:00Z',
    rawInputHash: 'hash',
  },
  tags: [],
  catalysts: [],
  risks: [],
  valuationRefs: [],
  priority: 'normal',
  pinned: false,
  archived: false,
  revision: 1,
};

const projection: WorkspaceProjection = {
  workspace,
  activeView: 'canvas',
  notes: [note],
  links: [],
  ghosts: [],
  memoBlocks: [],
  graphNodes: [],
  graphEdges: [],
  kanbanColumns: [],
  timelineEvents: [],
};

describe('ResearchEventSync helpers', () => {
  it('patches workspace and note updates into the query cache', () => {
    const queryClient = new QueryClient();
    queryClient.setQueryData(researchQueryKeys.workspaces, [workspace]);
    queryClient.setQueryData(researchQueryKeys.snapshot(workspace.id), projection);

    syncResearchWorkspaceEvent(queryClient, {
      workspaceId: workspace.id,
      workspace: {
        ...workspace,
        name: 'Updated Research',
      },
    });
    syncResearchNoteEvent(queryClient, {
      workspaceId: workspace.id,
      note: {
        ...note,
        title: 'Updated note',
      },
    });

    const updatedSnapshot = queryClient.getQueryData<WorkspaceProjection>(
      researchQueryKeys.snapshot(workspace.id),
    );
    expect(updatedSnapshot?.workspace.name).toBe('Updated Research');
    expect(updatedSnapshot?.notes[0].title).toBe('Updated note');
  });

  it('invalidates snapshot and jobs after completed link jobs', () => {
    const queryClient = new QueryClient();
    const invalidateQueries = mock(async () => undefined);
    queryClient.invalidateQueries = invalidateQueries as typeof queryClient.invalidateQueries;

    const job: PipelineJob = {
      id: 'job-1',
      workspaceId: workspace.id,
      entityId: note.id,
      jobKind: 'infer_links',
      status: 'completed',
      attemptCount: 1,
      maxAttempts: 3,
      payloadJson: {},
      createdAt: '2026-04-09T10:00:00Z',
      updatedAt: '2026-04-09T10:00:00Z',
    };

    syncResearchJobEvent(queryClient, {
      workspaceId: workspace.id,
      job,
    });

    expect(invalidateQueries).toHaveBeenCalledWith({
      queryKey: researchQueryKeys.snapshot(workspace.id),
    });
    expect(invalidateQueries).toHaveBeenCalledWith({
      queryKey: researchQueryKeys.jobs(workspace.id),
    });
    expect(invalidateQueries).toHaveBeenCalledWith({
      queryKey: ['research', 'auditTrail'],
    });
  });

  it('upserts ghost updates into the active snapshot', () => {
    const queryClient = new QueryClient();
    queryClient.setQueryData(researchQueryKeys.snapshot(workspace.id), projection);

    syncResearchGhostEvent(queryClient, {
      workspaceId: workspace.id,
      ghost: {
        id: 'ghost-1',
        workspaceId: workspace.id,
        ghostClass: 'candidate_thesis',
        headline: 'Candidate thesis',
        body: 'Margins may expand.',
        tone: 'tentative',
        confidence: 0.8,
        visibilityState: 'visible',
        state: 'accepted',
        supportingNoteIds: [note.id],
        contradictingNoteIds: [],
        sourceIds: [],
        evidenceThresholdMet: true,
        createdAt: '2026-04-09T10:00:00Z',
        updatedAt: '2026-04-09T10:00:00Z',
      },
    });

    const updatedSnapshot = queryClient.getQueryData<WorkspaceProjection>(
      researchQueryKeys.snapshot(workspace.id),
    );
    expect(updatedSnapshot?.ghosts[0]?.id).toBe('ghost-1');
  });
});
