import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, act, waitFor } from '@testing-library/react';
import { buildReferenceBlock, buildContextMeta, useTarotReading } from './useTarotReading';
import * as api from '../../../api';

const FOOL = { id: 0, slug: 'the-fool', name: '바보', nameEn: 'The Fool',
  arcana: 'major', element: 'air',
  keywords: ['새로운 시작','도약'], reversedKeywords: ['무모함'],
  meaningUpright: 'M-up', meaningReversed: 'M-rev' };
const LOVERS = { id: 6, slug: 'the-lovers', name: '연인', nameEn: 'The Lovers',
  arcana: 'major', element: 'air',
  keywords: ['사랑'], reversedKeywords: ['갈등'],
  meaningUpright: 'L-up', meaningReversed: 'L-rev' };
const TEN_OF_CUPS = { id: 31, slug: 'ten-of-cups', name: '컵 10', nameEn: 'Ten of Cups',
  arcana: 'minor', suit: 'cups', rank: 10, element: 'water',
  keywords: ['정서적 충만'], reversedKeywords: ['갈등'],
  meaningUpright: 'T-up', meaningReversed: 'T-rev' };

describe('buildReferenceBlock', () => {
  it('각 카드를 번호·위치·정역과 함께 포함한다', () => {
    const block = buildReferenceBlock([
      { card: FOOL, position: '과거', reversed: false },
      { card: LOVERS, position: '현재', reversed: true },
    ]);
    expect(block).toContain('1. 위치: 과거');
    expect(block).toContain('The Fool (정방향)');
    expect(block).toContain('2. 위치: 현재');
    expect(block).toContain('The Lovers (역방향)');
    expect(block).toContain('M-up');
    expect(block).toContain('L-rev');
  });
});

describe('buildContextMeta', () => {
  it('메이저:마이너 비율과 원소 분포·정역 흐름을 계산한다', () => {
    const meta = buildContextMeta([
      { card: FOOL, position: '과거', reversed: false },
      { card: LOVERS, position: '현재', reversed: true },
      { card: TEN_OF_CUPS, position: '미래', reversed: false },
    ]);
    expect(meta.major_minor_ratio).toBe('2:1');
    expect(meta.element_distribution.air).toBe(2);
    expect(meta.element_distribution.water).toBe(1);
    expect(meta.orientation_flow).toBe('upright→reversed→upright');
  });
});

describe('useTarotReading', () => {
  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it('runInterpretAndSave 시 interpret → save 순서로 호출한다', async () => {
    vi.spyOn(api, 'tarotInterpret').mockResolvedValue({
      interpretation_json: { summary: 'S', cards: [], interactions: [], advice: 'A', warning: null, confidence: 'high' },
      model: 'm', tokens_in: 1, tokens_out: 2, cost_usd: 0.01, latency_ms: 10, reroll_count: 0,
    });
    vi.spyOn(api, 'tarotSaveReading').mockResolvedValue({ id: 42, created_at: 't' });

    const { result } = renderHook(() => useTarotReading());
    await act(async () => {
      await result.current.runInterpretAndSave({
        spread_type: 'one_card',
        category: '일반',
        question: 'Q',
        picks: [{ card: FOOL, position: '오늘', reversed: false }],
      });
    });
    expect(api.tarotInterpret).toHaveBeenCalledTimes(1);
    expect(api.tarotSaveReading).toHaveBeenCalledTimes(1);
    expect(result.current.readingId).toBe(42);
    expect(result.current.interpretation.confidence).toBe('high');
  });

  it('interpret 실패 시 readingId는 null', async () => {
    vi.spyOn(api, 'tarotInterpret').mockRejectedValue(new Error('boom'));
    const saveSpy = vi.spyOn(api, 'tarotSaveReading');

    const { result } = renderHook(() => useTarotReading());
    await act(async () => {
      try {
        await result.current.runInterpretAndSave({
          spread_type: 'one_card', category: null, question: null,
          picks: [{ card: FOOL, position: '오늘', reversed: false }],
        });
      } catch { /* expected */ }
    });
    expect(saveSpy).not.toHaveBeenCalled();
    expect(result.current.readingId).toBe(null);
    expect(result.current.error).toBeTruthy();
  });
});
