/* @vitest-environment jsdom */

import { act, renderHook } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';

import {
  AnimationState,
  type GameState,
  type StoryMoment,
  type StoryOption,
  WorldType,
} from '../../types';
import { useRpgSceneTransitionModel } from './useRpgSceneTransitionModel';

function createGameState(actId: string): GameState {
  return {
    worldType: WorldType.WUXIA,
    customWorldProfile: null,
    playerCharacter: {
      id: 'hero',
      name: '测试主角',
      title: '游侠',
      description: '测试角色',
      backstory: '测试背景',
      avatar: '',
      portrait: '',
      assetFolder: '',
      assetVariant: '',
      attributes: {
        strength: 10,
        agility: 10,
        intelligence: 10,
        spirit: 10,
      },
      personality: '沉稳',
      skills: [],
      adventureOpenings: {},
    },
    runtimeStats: {
      playTimeMs: 0,
      lastPlayTickAt: null,
      hostileNpcsDefeated: 0,
      questsAccepted: 0,
      itemsUsed: 0,
      scenesTraveled: 0,
    },
    currentScene: 'Story',
    storyHistory: [{ text: '旧幕', options: [] }],
    storyEngineMemory: {
      discoveredFactIds: [],
      activeThreadIds: [],
      resolvedScarIds: [],
      recentCarrierIds: [],
      currentSceneActState: {
        sceneId: 'scene-1',
        chapterId: 'chapter-1',
        currentActId: actId,
        currentActIndex: actId === 'act-1' ? 0 : 1,
        completedActIds: actId === 'act-1' ? [] : ['act-1'],
        visitedActIds: [actId],
      },
    },
    characterChats: {},
    animationState: AnimationState.IDLE,
    currentEncounter: null,
    npcInteractionActive: false,
    currentScenePreset: {
      id: 'scene-1',
      name: '断桥旧哨',
      description: '测试场景',
      imageSrc: '/scene.png',
      treasureHints: [],
      npcs: [],
    },
    sceneHostileNpcs: [],
    playerX: 0,
    playerOffsetY: 0,
    playerFacing: 'right',
    playerActionMode: 'idle',
    scrollWorld: false,
    inBattle: false,
    playerHp: 100,
    playerMaxHp: 100,
    playerMana: 20,
    playerMaxMana: 20,
    playerSkillCooldowns: {},
    activeCombatEffects: [],
    playerCurrency: 0,
    playerInventory: [],
    playerEquipment: {
      weapon: null,
      armor: null,
      relic: null,
    },
    npcStates: {},
    quests: [],
    roster: [],
    companions: [],
    currentBattleNpcId: null,
    currentNpcBattleMode: null,
    currentNpcBattleOutcome: null,
    sparReturnEncounter: null,
    sparPlayerHpBefore: null,
    sparPlayerMaxHpBefore: null,
    sparStoryHistoryBefore: null,
  };
}

function createStory(
  text: string,
  options: StoryOption[] = [],
  deferredAutoChoice?: StoryOption,
): StoryMoment {
  return {
    text,
    options,
    deferredAutoChoice,
  };
}

describe('useRpgSceneTransitionModel', () => {
  afterEach(() => {
    vi.useRealTimers();
  });

  it('fires deferred auto choice only after entry and through the latest callback', () => {
    vi.useFakeTimers();
    const autoChoice: StoryOption = {
      functionId: 'npc_preview_talk',
      actionText: '与新角色交谈',
      text: '与新角色交谈',
      visuals: {
        playerAnimation: AnimationState.IDLE,
        playerMoveMeters: 0,
        playerOffsetY: 0,
        playerFacing: 'right',
        scrollWorld: false,
        monsterChanges: [],
      },
    };
    const firstCallback = vi.fn();
    const latestCallback = vi.fn();
    const initialState = createGameState('act-1');
    const initialStory = createStory('旧幕收束', [
      {
        functionId: 'story_continue_adventure',
        actionText: '继续冒险',
        text: '继续冒险',
        visuals: autoChoice.visuals,
      },
    ]);
    const nextStory = createStory('新幕入口', [autoChoice], autoChoice);

    const { result, rerender } = renderHook(
      (props: {
        gameState: GameState;
        currentStory: StoryMoment;
        onDeferredAutoChoice: (option: StoryOption) => void;
      }) =>
        useRpgSceneTransitionModel({
          gameState: props.gameState,
          currentStory: props.currentStory,
          openingCampSceneId: null,
          onDeferredAutoChoice: props.onDeferredAutoChoice,
        }),
      {
        initialProps: {
          gameState: initialState,
          currentStory: initialStory,
          onDeferredAutoChoice: firstCallback,
        },
      },
    );

    act(() => {
      result.current.setSceneTransitionDurations({ exitMs: 20, entryMs: 30 });
    });
    act(() => {
      result.current.beginSceneTransition('content-change');
    });

    expect(result.current.sceneTransitionPhase).toBe('exiting');

    rerender({
      gameState: createGameState('act-2'),
      currentStory: nextStory,
      onDeferredAutoChoice: latestCallback,
    });

    act(() => {
      vi.advanceTimersByTime(20);
    });

    expect(result.current.sceneTransitionPhase).toBe('entering');
    expect(latestCallback).not.toHaveBeenCalled();

    act(() => {
      vi.advanceTimersByTime(30);
    });

    expect(result.current.sceneTransitionPhase).toBe('idle');
    expect(firstCallback).not.toHaveBeenCalled();
    expect(latestCallback).toHaveBeenCalledWith(autoChoice);
  });
});
