import { describe, expect, it } from 'bun:test';
import {
  rebuildWorkspaceProjection,
  upsertProjectionGhost,
  upsertProjectionNote,
} from './researchProjection';
import type {
  GhostNote,
  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 = (overrides: Partial<ResearchNote> = {}): ResearchNote => ({
  id: 'note-1',
  workspaceId: workspace.id,
  ticker: 'NVDA',
  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,
  ...overrides,
});

const ghost = (overrides: Partial<GhostNote> = {}): GhostNote => ({
  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-1'],
  contradictingNoteIds: [],
  sourceIds: ['source-1'],
  evidenceThresholdMet: true,
  createdAt: '2026-04-09T10:00:00Z',
  updatedAt: '2026-04-09T10:00:00Z',
  memoSectionHint: 'investment_memo',
  ...overrides,
});

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

describe('researchProjection helpers', () => {
  it('upsertProjectionNote updates existing notes and recomputes derived views', () => {
    const updated = upsertProjectionNote(
      projection(),
      note({
        id: 'note-1',
        noteType: 'event_takeaway',
        title: 'Earnings reaction',
        sourceExcerpt: {
          sourceId: 'source-1',
          locationLabel: 'Q1 2026',
        },
      }),
    );

    expect(updated.notes[0].noteType).toBe('event_takeaway');
    expect(updated.timelineEvents).toEqual([
      {
        id: 'note-1',
        label: 'Earnings reaction',
        noteId: 'note-1',
        at: 'Q1 2026',
      },
    ]);
  });

  it('upsertProjectionGhost recomputes memo blocks for accepted ghosts', () => {
    const updated = upsertProjectionGhost(projection(), ghost());

    expect(updated.ghosts).toHaveLength(1);
    expect(updated.memoBlocks.some((block) => block.headline === 'Candidate thesis')).toBe(true);
  });
});
