import { describe, expect, it, mock } from 'bun:test';
import { createResearchBridge } from './researchBridge';

describe('createResearchBridge', () => {
  it('passes request payloads to the expected Tauri commands', async () => {
    const invoke = mock(
      async <T>(command: string, args?: Record<string, unknown>): Promise<T> => {
        switch (command) {
          case 'list_research_workspaces':
            return [] as T;
          case 'create_research_workspace':
            expect(args).toEqual({
              request: {
                name: 'NVDA Research',
                primaryTicker: 'NVDA',
              },
            });
            return {
              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',
            } as T;
          case 'capture_research_note':
            expect(args).toEqual({
              request: {
                workspaceId: 'workspace-1',
                rawText: 'Demand inflection may be forming.',
                ticker: 'NVDA',
              },
            });
            return {
              note: {
                id: 'note-1',
                workspaceId: 'workspace-1',
                rawText: 'Demand inflection may be forming.',
                cleanedText: 'Demand inflection may be forming.',
                noteType: 'claim',
                analystStatus: 'captured',
                confidence: 0.7,
                evidenceStatus: 'unsourced',
                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,
              },
              placementHint: {
                tileLane: 'normal',
                kanbanColumn: 'claim',
              },
              queuedJobs: [],
            } as T;
          case 'get_workspace_projection':
            expect(args).toEqual({
              request: {
                workspaceId: 'workspace-1',
                view: 'canvas',
              },
            });
            return {
              workspace: {
                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',
              },
              activeView: 'canvas',
              notes: [],
              links: [],
              ghosts: [],
              memoBlocks: [],
              graphNodes: [],
              graphEdges: [],
              kanbanColumns: [],
              timelineEvents: [],
            } as T;
          case 'review_ghost_note':
            expect(args).toEqual({
              request: {
                ghostNoteId: 'ghost-1',
                action: 'accept',
              },
            });
            return {
              id: 'ghost-1',
              workspaceId: 'workspace-1',
              ghostClass: 'candidate_thesis',
              headline: 'Possible thesis',
              body: 'Observed: ...',
              tone: 'tentative',
              confidence: 0.9,
              visibilityState: 'visible',
              state: 'accepted',
              supportingNoteIds: [],
              contradictingNoteIds: [],
              sourceIds: [],
              evidenceThresholdMet: true,
              createdAt: '2026-04-09T10:00:00Z',
              updatedAt: '2026-04-09T10:00:00Z',
            } as T;
          default:
            throw new Error(`Unexpected command: ${command}`);
        }
      },
    );

    const bridge = createResearchBridge(invoke);
    const workspaces = await bridge.listResearchWorkspaces();
    const workspace = await bridge.createResearchWorkspace({
      name: 'NVDA Research',
      primaryTicker: 'NVDA',
    });
    const capture = await bridge.captureResearchNote({
      workspaceId: 'workspace-1',
      rawText: 'Demand inflection may be forming.',
      ticker: 'NVDA',
    });
    const projection = await bridge.getWorkspaceProjection({
      workspaceId: 'workspace-1',
      view: 'canvas',
    });
    const ghost = await bridge.reviewGhostNote({
      ghostNoteId: 'ghost-1',
      action: 'accept',
    });

    expect(workspaces).toEqual([]);
    expect(workspace.primaryTicker).toBe('NVDA');
    expect(capture.note.id).toBe('note-1');
    expect(projection.activeView).toBe('canvas');
    expect(ghost.state).toBe('accepted');
  });

  it('subscribes to the research event channels', async () => {
    const listen = mock(
      async <T>(
        event: string,
        handler: (event: { payload: T }) => void,
      ): Promise<() => void> => {
        if (event === 'research_workspace_updated') {
          handler({
            payload: {
              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',
            } as T,
          });
        } else if (event === 'research_note_updated') {
          handler({
            payload: {
              id: 'note-1',
              workspaceId: 'workspace-1',
            } as T,
          });
        } else if (event === 'research_ghost_updated') {
          handler({
            payload: {
              id: 'ghost-1',
              workspaceId: 'workspace-1',
            } as T,
          });
        } else {
          handler({
            payload: {
              id: 'job-1',
              workspaceId: 'workspace-1',
            } as T,
          });
        }
        return () => {};
      },
    );
    const bridge = createResearchBridge(async () => undefined as never, listen);
    const workspaceHandler = mock(() => {});
    const noteHandler = mock(() => {});
    const ghostHandler = mock(() => {});
    const jobHandler = mock(() => {});

    await bridge.listenForWorkspaceUpdates(workspaceHandler);
    await bridge.listenForNoteUpdates(noteHandler);
    await bridge.listenForGhostUpdates(ghostHandler);
    await bridge.listenForJobUpdates(jobHandler);

    expect(listen).toHaveBeenCalledWith(
      'research_workspace_updated',
      expect.any(Function),
    );
    expect(listen).toHaveBeenCalledWith(
      'research_note_updated',
      expect.any(Function),
    );
    expect(listen).toHaveBeenCalledWith(
      'research_ghost_updated',
      expect.any(Function),
    );
    expect(listen).toHaveBeenCalledWith(
      'research_job_updated',
      expect.any(Function),
    );
    expect(workspaceHandler).toHaveBeenCalledWith({
      workspaceId: 'workspace-1',
      workspace: {
        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',
      },
    });
    expect(noteHandler).toHaveBeenCalledWith({
      workspaceId: 'workspace-1',
      note: {
        id: 'note-1',
        workspaceId: 'workspace-1',
      },
    });
    expect(ghostHandler).toHaveBeenCalledWith({
      workspaceId: 'workspace-1',
      ghost: {
        id: 'ghost-1',
        workspaceId: 'workspace-1',
      },
    });
    expect(jobHandler).toHaveBeenCalledWith({
      workspaceId: 'workspace-1',
      job: {
        id: 'job-1',
        workspaceId: 'workspace-1',
      },
    });
  });
});
