import { RotateCcw } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';

import { getCharacterAnimationDurationMs, getSkillCasterAnimation, getSkillDelivery } from '../data/characterCombat';
import { ROLE_TEMPLATE_CHARACTERS } from '../data/characterPresets';
import { createSceneHostileNpcsFromIds } from '../data/hostileNpcs';
import { buildInitialNpcState, createNpcBattleMonster } from '../data/npcInteractions';
import { getScenePreset } from '../data/scenePresets';
import { buildSkillEffects } from '../hooks/useCombatFlow';
import {
  AnimationState,
  Character,
  CharacterSkillDefinition,
  CombatActionMode,
  CombatVisualEffect,
  Encounter,
  SceneHostileNpc,
  WorldType,
} from '../types';
import { PlatformActionButton } from './common/PlatformActionButton';
import { GameCanvas } from './GameCanvas';

export interface SkillEffectPreviewProps {
  mode: 'player' | 'npc';
  worldType: WorldType;
  character: Character;
  skill: CharacterSkillDefinition | null;
  targetMonsterId?: string | null;
  npcEncounter?: Encounter | null;
  targetCharacter?: Character | null;
}

const PLAYER_X = 0;

function getSkillReleaseDelayMs(character: Character, skill: CharacterSkillDefinition) {
  if (typeof skill.releaseDelayMs === 'number') return skill.releaseDelayMs;
  const animationDuration = getCharacterAnimationDurationMs(character, getSkillCasterAnimation(skill));
  return Math.min(260, Math.max(120, Math.round(animationDuration * 0.45)));
}

function buildPreviewTargetMonster(worldType: WorldType, targetMonsterId?: string | null) {
  const previewMonster = createSceneHostileNpcsFromIds(
    worldType,
    targetMonsterId ? [targetMonsterId] : [],
    PLAYER_X,
  )[0];

  return previewMonster
    ? {
        ...previewMonster,
        xMeters: 3.2,
        animation: 'idle' as const,
        action: `${previewMonster.name}站稳架势，等待受击`,
      }
    : null;
}

function resetNpcPreviewMonster(monster: SceneHostileNpc) {
  return {
    ...monster,
    animation: 'idle' as const,
    action: `${monster.name}准备出招`,
    characterAnimation: undefined,
    combatMode: undefined,
  };
}

export function SkillEffectPreview({
  mode,
  worldType,
  character,
  skill,
  targetMonsterId,
  npcEncounter,
  targetCharacter,
}: SkillEffectPreviewProps) {
  const scenePreset = useMemo(() => getScenePreset(worldType, 0), [worldType]);
  const fallbackTargetCharacter = useMemo(
    () => targetCharacter ?? ROLE_TEMPLATE_CHARACTERS.find(candidate => candidate.id !== character.id) ?? ROLE_TEMPLATE_CHARACTERS[0] ?? character,
    [character, targetCharacter],
  );

  const initialMonsters = useMemo(() => {
    if (mode === 'player') {
      const monster = buildPreviewTargetMonster(worldType, targetMonsterId);
      return monster ? [monster] : [];
    }

    if (!npcEncounter) return [];
    return [
      createNpcBattleMonster(
        npcEncounter,
        buildInitialNpcState(npcEncounter, worldType),
        'fight',
        {
          worldType,
        },
      ),
    ];
  }, [mode, npcEncounter, targetMonsterId, worldType]);

  const [playerAnimation, setPlayerAnimation] = useState(AnimationState.IDLE);
  const [playerActionMode, setPlayerActionMode] = useState<CombatActionMode>('idle');
  const [sceneHostileNpcs, setSceneMonsters] = useState<SceneHostileNpc[]>(initialMonsters);
  const [activeCombatEffects, setActiveCombatEffects] = useState<CombatVisualEffect[]>([]);
  const [restartTick, setRestartTick] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);

  useEffect(() => {
    setSceneMonsters(initialMonsters);
    setPlayerAnimation(AnimationState.IDLE);
    setPlayerActionMode('idle');
    setActiveCombatEffects([]);
    setIsPlaying(false);
  }, [initialMonsters, skill?.id]);

  useEffect(() => {
    if (!skill || !scenePreset) return;

    let active = true;
    const timers: number[] = [];
    const casterAnimation = getSkillCasterAnimation(skill);
    const delivery = getSkillDelivery(skill);
    const attackerFacing = mode === 'player' ? 'right' : 'left';
    const primaryMonster = initialMonsters[0] ?? null;

    if (mode === 'player') {
      setPlayerAnimation(casterAnimation);
      setPlayerActionMode(delivery);
      setSceneMonsters(initialMonsters.map(monster => ({
        ...monster,
        action: `${monster.name}正面承受${skill.name}的预览`,
      })));
    } else {
      setPlayerAnimation(AnimationState.IDLE);
      setPlayerActionMode('idle');
      setSceneMonsters(initialMonsters.map(monster => ({
        ...resetNpcPreviewMonster(monster),
        action: `${monster.name}施展${skill.name}`,
        characterAnimation: casterAnimation,
        combatMode: delivery,
      })));
    }

    setIsPlaying(true);

    const phases = primaryMonster
      ? buildSkillEffects(
          {
            character,
            xMeters: mode === 'player' ? PLAYER_X : primaryMonster.xMeters,
            origin: mode === 'player' ? 'player' : 'monster',
            facing: attackerFacing,
            monsterId: mode === 'player' ? undefined : primaryMonster.id,
          },
          {
            xMeters: mode === 'player' ? primaryMonster.xMeters : PLAYER_X,
            origin: mode === 'player' ? 'monster' : 'player',
            monsterId: mode === 'player' ? primaryMonster.id : undefined,
          },
          skill,
        )
      : {
          cast: [] as CombatVisualEffect[],
          travel: [] as CombatVisualEffect[],
          impact: [] as CombatVisualEffect[],
          castDurationMs: 0,
          travelDurationMs: 0,
          impactDurationMs: 0,
        };

    const releaseDelay = (skill.effects?.length ?? 0) > 0
      ? getSkillReleaseDelayMs(character, skill)
      : getCharacterAnimationDurationMs(character, casterAnimation);

    let delay = releaseDelay;

    const schedule = (taskDelay: number, task: () => void) => {
      timers.push(window.setTimeout(() => {
        if (!active) return;
        task();
      }, taskDelay));
    };

    if (phases.cast.length > 0) {
      schedule(delay, () => setActiveCombatEffects(phases.cast));
      delay += phases.castDurationMs;
    }

    if (phases.travel.length > 0) {
      schedule(delay, () => setActiveCombatEffects(phases.travel));
      delay += phases.travelDurationMs;
    }

    if (phases.impact.length > 0) {
      schedule(delay, () => {
        setActiveCombatEffects(phases.impact);
        if (mode === 'player') {
          setSceneMonsters(current => current.map(monster => ({
            ...monster,
            action: `${monster.name}被${skill.name}命中`,
          })));
        }
      });
      delay += phases.impactDurationMs;
    }

    schedule(delay, () => {
      setActiveCombatEffects([]);
      setPlayerAnimation(AnimationState.IDLE);
      setPlayerActionMode('idle');
      setSceneMonsters(initialMonsters.map(monster => resetNpcPreviewMonster(monster)));
      setIsPlaying(false);
    });

    return () => {
      active = false;
      timers.forEach(timerId => window.clearTimeout(timerId));
    };
  }, [character, initialMonsters, mode, restartTick, scenePreset, skill]);

  return (
    <div className="rounded-2xl border border-white/10 bg-black/20 p-4">
      <div className="mb-3 flex items-center justify-between gap-3">
        <div>
          <div className="text-sm font-semibold text-white">{skill?.name ?? '未选择技能'}</div>
          <div className="mt-1 text-xs text-zinc-400">
            {mode === 'player' ? `受击对象：${sceneHostileNpcs[0]?.name ?? '无目标'}` : `受击对象：${fallbackTargetCharacter.name}`}
          </div>
        </div>
        <PlatformActionButton
          onClick={() => setRestartTick(value => value + 1)}
          disabled={!skill || isPlaying}
          surface="editorDark"
          tone="ghost"
          size="xs"
          className="min-h-0 rounded-lg bg-black/30 px-3 py-2 text-xs hover:border-white/20 disabled:opacity-50"
        >
          <RotateCcw className="h-3.5 w-3.5" />
          <span>{isPlaying ? '播放中' : '重新预览'}</span>
        </PlatformActionButton>
      </div>

      <div className="overflow-hidden rounded-2xl border border-white/10 bg-black">
        <div className="h-[300px]">
          <GameCanvas
            scrollWorld={false}
            animationState={playerAnimation}
            playerCharacter={fallbackTargetCharacter && mode === 'npc' ? fallbackTargetCharacter : character}
            encounter={null}
            currentScenePreset={scenePreset}
            worldType={worldType}
            customWorldProfile={null}
            storyEngineMemory={null}
            sceneHostileNpcs={sceneHostileNpcs}
            playerX={PLAYER_X}
            playerOffsetY={0}
            playerFacing="right"
            playerActionMode={mode === 'player' ? playerActionMode : 'idle'}
            inBattle
            playerHp={180}
            playerMaxHp={180}
            activeCombatEffects={activeCombatEffects}
            onSceneNameClick={null}
          />
        </div>
      </div>
    </div>
  );
}
