import { describe, expect, it } from 'vitest';
import {
  buildOcrMetaFromIdentifyResult,
  buildScannedCardPayload,
  candidateMatchesSetHint,
  resolveDisambiguationRefineAction,
  resolveIdentifyOutcome,
} from '../../lib/scanner-card-identify.js';

describe('candidateMatchesSetHint', () => {
  it('matches when set code equals hint', () => {
    expect(candidateMatchesSetHint({ set_name: 'Base Set', set_code: 'BS' }, null, 'BS')).toBe(true);
  });

  it('returns true when no hint is provided', () => {
    expect(candidateMatchesSetHint({ set_name: 'Any Set' }, null, null)).toBe(true);
  });

  it('returns false for unrelated sets', () => {
    expect(candidateMatchesSetHint({ set_name: 'Jungle', set_code: 'JU' }, 'Base Set', null)).toBe(false);
  });
});

describe('resolveIdentifyOutcome', () => {
  it('returns emit when a single card is matched', () => {
    const card = { id: 1, name: 'Pikachu', mana_cost: '1R' };
    const outcome = resolveIdentifyOutcome({
      isCard: true,
      card,
      ocr: { confidence: 90, rawText: 'Pikachu' },
    });

    expect(outcome).toMatchObject({
      type: 'emit',
      cardStatus: 'confirmed',
      card,
    });
    expect(outcome.ocrMeta.confidence).toBe(90);
  });

  it('returns disambiguation when multiple printings match', () => {
    const matches = [{ id: 1, name: 'Lightning Bolt' }, { id: 2, name: 'Lightning Bolt' }];
    const outcome = resolveIdentifyOutcome({
      isCard: true,
      needsUserSelection: true,
      matches,
      message: 'Pick one',
    });

    expect(outcome).toEqual({
      type: 'disambiguation',
      cardStatus: 'confirmed',
      matches,
      ocrMeta: expect.objectContaining({ abilities: [] }),
      message: 'Pick one',
    });
  });

  it('returns error when the frame is not a card', () => {
    expect(resolveIdentifyOutcome({ isCard: false, reason: 'Blurry' })).toEqual({
      type: 'error',
      cardStatus: 'negative',
      message: 'Blurry',
    });
  });
});

describe('buildScannedCardPayload', () => {
  it('maps catalog fields and OCR metadata into the scanner queue shape', () => {
    const payload = buildScannedCardPayload(
      {
        id: 42,
        name: 'Seel',
        set_name: 'Perfect Order',
        set_code: 'PO',
        card_number: '015/208',
        game: 'pokemon',
        card_type: 'Pokemon',
        rarity: 'Common',
        image_url: 'https://example.com/seel.jpg',
      },
      {
        imageData: 'data:image/jpeg;base64,abc',
        scanImageUrl: 'https://blob.example/seel.jpg',
        ocrMeta: { rawText: 'Seel', confidence: 88, abilities: ['Freeze-Dry'] },
      }
    );

    expect(payload).toMatchObject({
      name: 'Seel',
      set: 'Perfect Order',
      databaseId: 42,
      scanImageUrl: 'https://blob.example/seel.jpg',
      ocrText: 'Seel',
      confidence: 88,
      abilities: ['Freeze-Dry'],
    });
  });
});

describe('resolveDisambiguationRefineAction', () => {
  const candidates = [
    { id: 1, name: 'Bolt', set_name: 'Alpha', set_code: 'LEA' },
    { id: 2, name: 'Bolt', set_name: 'Beta', set_code: 'LEB' },
  ];

  it('auto-picks when vision narrows to one printing', () => {
    const action = resolveDisambiguationRefineAction(
      {
        matches: [{ id: 1 }],
        ocr: { setCode: 'LEA' },
      },
      { candidates }
    );

    expect(action).toEqual({ type: 'pick', candidate: candidates[0] });
  });

  it('requests admin review path when set hint misses the catalog', () => {
    const action = resolveDisambiguationRefineAction(
      {
        matches: [{}],
        ocr: { setName: 'Unknown Set', cardName: 'Bolt' },
      },
      { candidates }
    );

    expect(action.type).toBe('catalog_gap');
    expect(action.submitPayload.candidateCardIds).toEqual([1, 2]);
  });
});

describe('buildOcrMetaFromIdentifyResult', () => {
  it('prefers top-level OCR fields over nested card OCR', () => {
    expect(
      buildOcrMetaFromIdentifyResult({
        ocr: { confidence: 95, rawText: 'From top' },
        card: { ocr: { confidence: 50, rawText: 'From card', abilities: ['Flying'] }, hp: 4 },
      })
    ).toMatchObject({
      confidence: 95,
      rawText: 'From top',
      abilities: ['Flying'],
      hp: 4,
    });
  });
});
