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

describe('createMappingsBridge', () => {
  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_custom_mappings':
            return [] as T;
          case 'get_custom_mapping':
            expect(args).toEqual({ id: 'mapping-1' });
            return {
              id: 'mapping-1',
              targetField: 'total_revenues',
              mappingKind: {
                concept: {
                  taxonomy: 'us-gaap',
                  concept:
                    'RevenueFromContractWithCustomerExcludingAssessedTax',
                  unitFamily: 'currency',
                },
              },
              scope: { ticker: 'AAPL' },
              enabled: true,
            } as T;
          case 'add_custom_mapping':
            expect(args).toEqual({
              mapping: {
                id: 'mapping-2',
                targetField: 'gross_profit',
                mappingKind: {
                  concept: {
                    taxonomy: 'us-gaap',
                    concept: 'GrossProfit',
                    unitFamily: 'currency',
                  },
                },
                scope: { ticker: 'AAPL' },
                enabled: true,
              },
            });
            return 'mapping-2' as T;
          case 'update_custom_mapping':
            expect(args).toEqual({
              id: 'mapping-2',
              mapping: {
                id: 'mapping-2',
                targetField: 'gross_profit',
                mappingKind: {
                  concept: {
                    taxonomy: 'us-gaap',
                    concept: 'GrossProfit',
                    unitFamily: 'currency',
                  },
                },
                scope: { ticker: 'AAPL' },
                enabled: true,
              },
            });
            return undefined as T;
          case 'delete_custom_mapping':
            expect(args).toEqual({ id: 'mapping-2' });
            return undefined as T;
          case 'toggle_custom_mapping':
            expect(args).toEqual({ id: 'mapping-2' });
            return true as T;
          case 'import_mappings':
            expect(args).toEqual({ json: '{"mappings":[]}' });
            return {
              version: 1,
              lastUpdated: '2026-04-13T10:00:00Z',
              mappings: [],
            } as T;
          case 'export_mappings':
            return '{"mappings":[]}' as T;
          default:
            throw new Error(`Unexpected command: ${command}`);
        }
      },
    );

    const bridge = createMappingsBridge(invoke);

    expect(await bridge.listMappings()).toEqual([]);
    expect((await bridge.getMapping('mapping-1')).id).toBe('mapping-1');
    expect(
      await bridge.addMapping({
        id: 'mapping-2',
        targetField: 'gross_profit',
        mappingKind: {
          concept: {
            taxonomy: 'us-gaap',
            concept: 'GrossProfit',
            unitFamily: 'currency',
          },
        },
        scope: { ticker: 'AAPL' },
        enabled: true,
      }),
    ).toBe('mapping-2');
    await bridge.updateMapping('mapping-2', {
      id: 'mapping-2',
      targetField: 'gross_profit',
      mappingKind: {
        concept: {
          taxonomy: 'us-gaap',
          concept: 'GrossProfit',
          unitFamily: 'currency',
        },
      },
      scope: { ticker: 'AAPL' },
      enabled: true,
    });
    await bridge.deleteMapping('mapping-2');
    expect(await bridge.toggleMapping('mapping-2')).toBe(true);
    expect(await bridge.importMappings('{"mappings":[]}')).toEqual({
      version: 1,
      lastUpdated: '2026-04-13T10:00:00Z',
      mappings: [],
    });
    expect(await bridge.exportMappings()).toBe('{"mappings":[]}');
  });

  it('subscribes to mappings updates with the expected event name', async () => {
    const listen = mock(
      async <T>(
        _event: string,
        handler: (event: { payload: T }) => void,
      ): Promise<() => void> => {
        handler({
          payload: {
            changeKind: 'created',
            refreshScope: {
              fullRefresh: false,
              affectedScopes: [{ ticker: 'AAPL' }],
              affectedTargets: ['total_revenues'],
            },
          } as T,
        });
        return () => {};
      },
    );
    const handler = mock(() => {});
    const bridge = createMappingsBridge(async () => undefined as never, listen);

    await bridge.listenForUpdates(handler);

    expect(listen).toHaveBeenCalledWith(
      'mappings_updated',
      expect.any(Function),
    );
    expect(handler).toHaveBeenCalledWith({
      changeKind: 'created',
      refreshScope: {
        fullRefresh: false,
        affectedScopes: [{ ticker: 'AAPL' }],
        affectedTargets: ['total_revenues'],
      },
    });
  });
});
