import 'dart:async';

import 'package:flutter/material.dart';

import 'package:asciineverdie/src/shared/animation/ascii_animation_data.dart';
import 'package:asciineverdie/src/shared/widgets/ascii_disintegrate_widget.dart';
import 'package:asciineverdie/src/shared/animation/ascii_animation_type.dart';
import 'package:asciineverdie/src/shared/animation/background_layer.dart';
import 'package:asciineverdie/src/shared/animation/canvas/ascii_canvas_widget.dart';
import 'package:asciineverdie/src/shared/animation/canvas/ascii_layer.dart';
import 'package:asciineverdie/src/shared/animation/canvas/canvas_battle_composer.dart';
import 'package:asciineverdie/src/shared/animation/canvas/canvas_special_composer.dart';
import 'package:asciineverdie/src/shared/animation/canvas/canvas_town_composer.dart';
import 'package:asciineverdie/src/shared/animation/canvas/canvas_walking_composer.dart';
import 'package:asciineverdie/src/shared/animation/character_frames.dart';
import 'package:asciineverdie/src/shared/animation/monster_size.dart';
import 'package:asciineverdie/src/shared/animation/weapon_category.dart';
import 'package:asciineverdie/src/shared/theme/ascii_colors.dart';
import 'package:asciineverdie/src/core/model/combat_event.dart';
import 'package:asciineverdie/src/core/model/game_state.dart';
import 'package:asciineverdie/src/core/model/item_stats.dart';
import 'package:asciineverdie/src/core/model/monster_grade.dart';
import 'package:asciineverdie/src/features/game/widgets/combat_event_mapping.dart';

/// 애니메이션 모드
enum AnimationMode {
  battle, // 전투
  walking, // 걷기
  town, // 마을/상점
  special, // 특수 이벤트
}

/// ASCII 애니메이션 카드 위젯 (전체 Canvas 기반)
///
/// TaskType에 따라 다른 애니메이션을 표시.
/// 전투 시 몬스터 이름에 따라 다른 애니메이션 선택.
/// 특수 이벤트(레벨업, 퀘스트 완료) 시 오버라이드 애니메이션 재생.
/// 자체 타이머로 프레임 전환 (게임 틱과 독립).
class AsciiAnimationCard extends StatefulWidget {
  const AsciiAnimationCard({
    super.key,
    required this.taskType,
    this.monsterBaseName,
    this.colorTheme = AsciiColorTheme.green,
    this.specialAnimation,
    this.weaponName,
    this.shieldName,
    this.characterLevel,
    this.monsterLevel,
    this.monsterGrade,
    this.monsterSize,
    this.isPaused = false,
    this.isInCombat = true,
    this.monsterDied = false,
    this.latestCombatEvent,
    this.raceId,
    this.weaponRarity,
    this.opponentRaceId,
    this.opponentHasShield = false,
  });

  final TaskType taskType;

  /// 일시정지 상태 (true면 애니메이션 정지)
  final bool isPaused;

  /// 전투 활성 상태 (false면 kill 태스크여도 walking 애니메이션)
  final bool isInCombat;

  /// 몬스터 사망 여부 (true면 분해 애니메이션 재생)
  final bool monsterDied;

  /// 전투 중인 몬스터 기본 이름 (kill 타입일 때만 사용)
  final String? monsterBaseName;
  final AsciiColorTheme colorTheme;

  /// 특수 애니메이션 오버라이드 (레벨업, 퀘스트 완료 등)
  /// 설정되면 일반 애니메이션 대신 표시
  final AsciiAnimationType? specialAnimation;

  /// 현재 장착 무기 이름 (공격 스타일 결정용)
  final String? weaponName;

  /// 현재 장착 방패 이름 (방패 표시용)
  final String? shieldName;

  /// 캐릭터 레벨
  final int? characterLevel;

  /// 몬스터 레벨 (전투 스탯 계산용)
  final int? monsterLevel;

  /// 몬스터 등급 (Normal/Elite/Boss) - 색상/접두사 표시용
  final MonsterGrade? monsterGrade;

  /// 몬스터 사이즈 (애니메이션 크기 결정용, Act 기반)
  final MonsterSize? monsterSize;

  /// 최근 전투 이벤트 (애니메이션 동기화용)
  final CombatEvent? latestCombatEvent;

  /// 종족 ID (Phase 4: 종족별 캐릭터 애니메이션)
  final String? raceId;

  /// 무기 희귀도 (Phase 9: 무기 등급별 이펙트 색상)
  final ItemRarity? weaponRarity;

  /// 상대 종족 ID (PvP 모드: 설정 시 몬스터 대신 캐릭터 표시)
  final String? opponentRaceId;

  /// 상대 방패 장착 여부 (PvP 모드)
  final bool opponentHasShield;

  @override
  State<AsciiAnimationCard> createState() => _AsciiAnimationCardState();
}

class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
  Timer? _timer;
  int _currentFrame = 0;
  AsciiAnimationType? _currentSpecialAnimation;

  // 애니메이션 모드
  AnimationMode _animationMode = AnimationMode.walking;

  // Composer 인스턴스들
  CanvasBattleComposer? _battleComposer;
  CanvasWalkingComposer? _walkingComposer;
  CanvasTownComposer? _townComposer;
  final _specialComposer = const CanvasSpecialComposer();

  // 전투 애니메이션 상태
  BattlePhase _battlePhase = BattlePhase.idle;
  int _battleSubFrame = 0;

  // 글로벌 틱 (배경 스크롤용)
  int _globalTick = 0;

  // 특수 애니메이션 틱 카운터 (프레임 간격 계산용)
  int _specialTick = 0;

  // 환경 타입
  EnvironmentType _environment = EnvironmentType.forest;

  // 전투 페이즈 시퀀스 (반복)
  static const _battlePhaseSequence = [
    (BattlePhase.idle, 4), // 4 프레임 대기
    (BattlePhase.prepare, 2), // 2 프레임 준비
    (BattlePhase.attack, 3), // 3 프레임 공격
    (BattlePhase.hit, 2), // 2 프레임 히트
    (BattlePhase.recover, 2), // 2 프레임 복귀
  ];
  int _phaseIndex = 0;
  int _phaseFrameCount = 0;

  // 전투 이벤트 동기화용 (Phase 5)
  int? _lastEventTimestamp;
  bool _showCriticalEffect = false;
  bool _showBlockEffect = false;
  bool _showParryEffect = false;
  bool _showSkillEffect = false;

  // 추가 전투 이펙트 (Phase 11)
  bool _showEvadeEffect = false;
  bool _showMissEffect = false;
  bool _showDebuffEffect = false;
  bool _showDotEffect = false;

  // 공격 속도 기반 동적 페이즈 프레임 수 (Phase 6)
  int _eventDrivenPhaseFrames = 0;
  bool _isEventDrivenPhase = false;

  // 공격자 타입 (Phase 7: 공격자별 위치 분리)
  AttackerType _currentAttacker = AttackerType.none;

  // 특수 애니메이션 프레임 수는 ascii_animation_type.dart의
  // specialAnimationFrameCounts 상수 사용

  // 몬스터 사망 분해 애니메이션 상태
  bool _showDeathAnimation = false;
  List<String>? _deathAnimationMonsterLines;
  String? _lastMonsterBaseName;
  int? _lastMonsterLevel; // 몬스터 레벨 캐시 (사망 시 스탯용)
  MonsterSize? _lastMonsterSize; // 몬스터 사이즈 캐시 (사망 시 크기 결정용)

  @override
  void initState() {
    super.initState();
    _updateAnimation();
  }

  @override
  void didUpdateWidget(AsciiAnimationCard oldWidget) {
    super.didUpdateWidget(oldWidget);

    // 일시정지 상태 변경 처리
    if (oldWidget.isPaused != widget.isPaused) {
      if (widget.isPaused) {
        _timer?.cancel();
        _timer = null;
      } else {
        // 재개 시: specialAnimation 동기화 (isPaused와 동시에 변경될 수 있음)
        // 예: 부활 시 isPaused가 true→false로 바뀌면서 동시에
        // specialAnimation이 null→resurrection으로 변경됨
        if (widget.specialAnimation != _currentSpecialAnimation) {
          _currentSpecialAnimation = widget.specialAnimation;
          _updateAnimation(); // _updateAnimation이 타이머 재시작도 처리함
          return;
        }
        // 일반 재개: 애니메이션 재시작 (현재 프레임 유지)
        _restartTimer();
      }
      return;
    }

    // 특수 애니메이션이 변경되었으면 업데이트
    if (oldWidget.specialAnimation != widget.specialAnimation) {
      _currentSpecialAnimation = widget.specialAnimation;
      _updateAnimation();
      return;
    }

    // 특수 애니메이션이 활성화되어 있으면 일반 업데이트 무시
    if (_currentSpecialAnimation != null) {
      return;
    }

    // 몬스터 사망 애니메이션 트리거
    if (!oldWidget.monsterDied && widget.monsterDied && !_showDeathAnimation) {
      // 현재 몬스터 프레임 캡처 (분해 애니메이션용)
      _deathAnimationMonsterLines = _captureMonsterFrame();
      if (_deathAnimationMonsterLines != null) {
        setState(() {
          _showDeathAnimation = true;
        });
        // 분해 애니메이션은 오버레이로 표시되므로
        // 백그라운드 상태 업데이트는 계속 진행 (20배속 대응)
      }
    }

    // 전투 이벤트 동기화 (Phase 5)
    if (widget.latestCombatEvent != null &&
        widget.latestCombatEvent!.timestamp != _lastEventTimestamp) {
      _handleCombatEvent(widget.latestCombatEvent!);
    }

    // 몬스터 정보 저장 (사망 시 프레임 캡처용)
    if (widget.monsterBaseName != null) {
      _lastMonsterBaseName = widget.monsterBaseName;
    }
    if (widget.monsterLevel != null) {
      _lastMonsterLevel = widget.monsterLevel;
    }
    if (widget.monsterSize != null) {
      _lastMonsterSize = widget.monsterSize;
    }

    // 새 몬스터 등장 시 사망 애니메이션 상태 리셋
    // (이전 몬스터 사망 애니메이션이 끝나기 전에 새 전투 시작 시 대응)
    if (oldWidget.monsterBaseName != widget.monsterBaseName &&
        widget.monsterBaseName != null) {
      _showDeathAnimation = false;
      _deathAnimationMonsterLines = null;
    }

    if (oldWidget.taskType != widget.taskType ||
        oldWidget.monsterBaseName != widget.monsterBaseName ||
        oldWidget.weaponName != widget.weaponName ||
        oldWidget.shieldName != widget.shieldName ||
        oldWidget.monsterLevel != widget.monsterLevel ||
        oldWidget.raceId != widget.raceId ||
        oldWidget.weaponRarity != widget.weaponRarity ||
        oldWidget.opponentRaceId != widget.opponentRaceId ||
        oldWidget.opponentHasShield != widget.opponentHasShield ||
        oldWidget.isInCombat != widget.isInCombat ||
        oldWidget.monsterDied != widget.monsterDied) {
      _updateAnimation();
    }
  }

  /// 전투 이벤트에 따라 애니메이션 페이즈 강제 전환 (Phase 5, 11)
  void _handleCombatEvent(CombatEvent event) {
    _lastEventTimestamp = event.timestamp;

    // 전투 모드가 아니면 무시
    if (_animationMode != AnimationMode.battle) return;

    final effects = mapCombatEventToEffects(event);

    setState(() {
      _battlePhase = effects.targetPhase;
      _battleSubFrame = 0;
      _phaseFrameCount = 0;
      _showCriticalEffect = effects.isCritical;
      _showBlockEffect = effects.isBlock;
      _showParryEffect = effects.isParry;
      _showSkillEffect = effects.isSkill;
      _showEvadeEffect = effects.isEvade;
      _showMissEffect = effects.isMiss;
      _showDebuffEffect = effects.isDebuff;
      _showDotEffect = effects.isDot;

      // 페이즈 인덱스 동기화
      _phaseIndex = _battlePhaseSequence.indexWhere(
        (p) => p.$1 == effects.targetPhase,
      );
      if (_phaseIndex < 0) _phaseIndex = 0;

      // 공격 속도에 따른 동적 페이즈 프레임 수 계산 (Phase 6)
      // 200ms tick 기준으로 프레임 수 계산 (최소 2, 최대 10)
      if (event.attackDelayMs != null && event.attackDelayMs! > 0) {
        _eventDrivenPhaseFrames = (event.attackDelayMs! ~/ 200).clamp(2, 10);
        _isEventDrivenPhase = true;
      } else {
        _isEventDrivenPhase = false;
      }

      // 공격자 타입 결정 (Phase 7: 공격자별 위치 분리)
      _currentAttacker = getAttackerType(event.type);
    });
  }

  /// 현재 상태를 유지하면서 타이머만 재시작
  void _restartTimer() {
    _timer?.cancel();
    _startTimer();
  }

  /// 타이머 시작
  void _startTimer() {
    const tickInterval = Duration(milliseconds: 200);

    _timer = Timer.periodic(tickInterval, (_) {
      if (!mounted) return;

      setState(() {
        _globalTick++;

        if (_animationMode == AnimationMode.special) {
          _specialTick++;
          // 특수 애니메이션 프레임 간격 계산 (200ms tick 기준)
          // 예: resurrection 600ms → 600/200 = 3 tick마다 1 프레임
          final frameInterval =
              (specialAnimationFrameIntervals[_currentSpecialAnimation] ??
                  200) ~/
              200;
          if (_specialTick >= frameInterval) {
            _specialTick = 0;
            _currentFrame++;
            final maxFrames =
                specialAnimationFrameCounts[_currentSpecialAnimation] ?? 5;
            // 마지막 프레임에 도달하면 특수 애니메이션 종료
            if (_currentFrame >= maxFrames) {
              _currentSpecialAnimation = null;
              _updateAnimation();
            }
          }
        } else if (_animationMode == AnimationMode.battle) {
          _advanceBattleFrame();
        }
        // walking, town은 globalTick만 증가하면 됨
      });
    });
  }

  void _updateAnimation() {
    _timer?.cancel();

    // 특수 애니메이션이 있으면 우선 적용
    if (_currentSpecialAnimation != null) {
      _animationMode = AnimationMode.special;
      _currentFrame = 0;
      _specialTick = 0;

      // 특수 애니메이션은 게임 일시정지와 무관하게 항상 재생
      _startTimer();
      return;
    }

    // 일반 애니메이션 처리
    final animationType = taskTypeToAnimation(widget.taskType);

    switch (animationType) {
      case AsciiAnimationType.battle:
        // 전투 비활성 상태면 walking 모드로 전환 (몬스터 처치 후 이동 중)
        if (!widget.isInCombat) {
          _animationMode = AnimationMode.walking;
          _walkingComposer = CanvasWalkingComposer(raceId: widget.raceId);
        } else {
          _animationMode = AnimationMode.battle;
          _setupBattleComposer();
          _battlePhase = BattlePhase.idle;
          _battleSubFrame = 0;
          _phaseIndex = 0;
          _phaseFrameCount = 0;
          // 새 전투 시작 시 사망 애니메이션 상태 리셋 (몬스터 숨김 방지)
          _showDeathAnimation = false;
          _deathAnimationMonsterLines = null;
        }

      case AsciiAnimationType.town:
        _animationMode = AnimationMode.town;
        _townComposer = CanvasTownComposer(raceId: widget.raceId);

      case AsciiAnimationType.walking:
        _animationMode = AnimationMode.walking;
        _walkingComposer = CanvasWalkingComposer(raceId: widget.raceId);

      default:
        _animationMode = AnimationMode.walking;
        _walkingComposer = CanvasWalkingComposer(raceId: widget.raceId);
    }

    // 일시정지 상태면 타이머 시작하지 않음
    if (widget.isPaused) return;

    _startTimer();
  }

  void _setupBattleComposer() {
    final weaponCategory = getWeaponCategory(widget.weaponName);
    final hasShield =
        widget.shieldName != null && widget.shieldName!.isNotEmpty;
    final monsterCategory = getMonsterCategory(widget.monsterBaseName);
    // Act 기반 사이즈 사용 (Phase 13), 없으면 레벨 기반 fallback
    final monsterSize =
        widget.monsterSize ?? getMonsterSize(widget.monsterLevel);

    _battleComposer = CanvasBattleComposer(
      weaponCategory: weaponCategory,
      hasShield: hasShield,
      monsterCategory: monsterCategory,
      monsterSize: monsterSize,
      raceId: widget.raceId,
      weaponRarity: widget.weaponRarity,
      opponentRaceId: widget.opponentRaceId,
      opponentHasShield: widget.opponentHasShield,
    );

    // 환경 타입 추론
    _environment = inferEnvironment(
      widget.taskType.name,
      widget.monsterBaseName,
    );
  }

  /// 현재 몬스터 프레임을 텍스트 라인으로 캡처 (분해 애니메이션용)
  List<String>? _captureMonsterFrame() {
    final monsterName = _lastMonsterBaseName ?? widget.monsterBaseName;
    if (monsterName == null) return null;

    final monsterCategory = getMonsterCategory(monsterName);
    // 캐시된 사이즈 사용 (사망 시점에 widget.monsterSize가 null일 수 있음)
    final monsterSize =
        _lastMonsterSize ??
        widget.monsterSize ??
        getMonsterSize(_lastMonsterLevel ?? widget.monsterLevel);

    // 몬스터 Idle 프레임 가져오기
    final frames = getMonsterIdleFrames(monsterCategory, monsterSize);
    if (frames.isEmpty) return null;

    return frames.first;
  }

  /// 사망 애니메이션 완료 콜백
  void _onDeathAnimationComplete() {
    setState(() {
      _showDeathAnimation = false;
      _deathAnimationMonsterLines = null;
    });
    // Walking 모드로 전환
    _updateAnimation();
  }

  void _advanceBattleFrame() {
    _phaseFrameCount++;
    final currentPhase = _battlePhaseSequence[_phaseIndex];

    // 현재 페이즈의 프레임 수 결정 (Phase 6)
    // 이벤트 기반 페이즈일 경우 공격 속도에 따른 동적 프레임 수 사용
    final targetFrames = _isEventDrivenPhase
        ? _eventDrivenPhaseFrames
        : currentPhase.$2;

    // 현재 페이즈의 프레임 수를 초과하면 다음 페이즈로
    if (_phaseFrameCount >= targetFrames) {
      _phaseIndex = (_phaseIndex + 1) % _battlePhaseSequence.length;
      _phaseFrameCount = 0;
      _battleSubFrame = 0;
      // 이펙트 리셋 (페이즈 전환 시)
      _showCriticalEffect = false;
      _showBlockEffect = false;
      _showParryEffect = false;
      _showSkillEffect = false;
      _showEvadeEffect = false;
      _showMissEffect = false;
      _showDebuffEffect = false;
      _showDotEffect = false;
      // 공격자 타입 및 이벤트 기반 페이즈 리셋 (idle 페이즈 진입 시에만)
      // 공격 사이클(prepare→attack→hit→recover) 동안 유지 (Bug fix)
      if (_battlePhaseSequence[_phaseIndex].$1 == BattlePhase.idle) {
        _currentAttacker = AttackerType.none;
        _isEventDrivenPhase = false;
      }
    } else {
      _battleSubFrame++;
    }

    _battlePhase = _battlePhaseSequence[_phaseIndex].$1;
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  /// 현재 애니메이션 레이어 생성
  List<AsciiLayer> _composeLayers() {
    return switch (_animationMode) {
      AnimationMode.battle =>
        _battleComposer?.composeLayers(
              _battlePhase,
              _battleSubFrame,
              widget.monsterBaseName,
              _environment,
              _globalTick,
              attacker: _currentAttacker,
              isCritical: _showCriticalEffect,
              isEvade: _showEvadeEffect,
              isMiss: _showMissEffect,
              isDebuff: _showDebuffEffect,
              isDot: _showDotEffect,
              isBlock: _showBlockEffect,
              isParry: _showParryEffect,
              hideMonster: _showDeathAnimation,
            ) ??
            [AsciiLayer.empty()],
      AnimationMode.walking =>
        _walkingComposer?.composeLayers(_globalTick) ?? [AsciiLayer.empty()],
      AnimationMode.town =>
        _townComposer?.composeLayers(_globalTick) ?? [AsciiLayer.empty()],
      AnimationMode.special => _specialComposer.composeLayers(
        _currentSpecialAnimation ?? AsciiAnimationType.levelUp,
        _currentFrame,
        _globalTick,
      ),
    };
  }

  @override
  Widget build(BuildContext context) {
    // 테마 인식 배경색 (다크: 검정, 라이트: 양피지)
    final bgColor = AsciiColors.backgroundOf(context);
    final positiveColor = AsciiColors.positiveOf(context);

    // 테두리 효과 결정 (전투 이벤트 또는 특수 애니메이션)
    final isSpecial = _currentSpecialAnimation != null;
    Border? borderEffect;
    if (_showCriticalEffect) {
      // 크리티컬 히트: 노란색 테두리
      borderEffect = Border.all(
        color: Colors.yellow.withValues(alpha: 0.8),
        width: 2,
      );
    } else if (_showBlockEffect) {
      // 블록 (방패 방어): 파란색 테두리
      borderEffect = Border.all(
        color: Colors.blue.withValues(alpha: 0.8),
        width: 2,
      );
    } else if (_showParryEffect) {
      // 패리 (무기 쳐내기): 주황색 테두리
      borderEffect = Border.all(
        color: Colors.orange.withValues(alpha: 0.8),
        width: 2,
      );
    } else if (_showSkillEffect) {
      // 스킬 사용: 마젠타 테두리
      borderEffect = Border.all(
        color: Colors.purple.withValues(alpha: 0.8),
        width: 2,
      );
    } else if (isSpecial) {
      // 특수 애니메이션: 포지티브 색상 테두리
      borderEffect = Border.all(color: positiveColor.withValues(alpha: 0.5));
    }

    return Container(
      padding: const EdgeInsets.all(4),
      decoration: BoxDecoration(
        color: bgColor,
        borderRadius: BorderRadius.circular(4),
        border: borderEffect,
      ),
      child: Stack(
        children: [
          // 기본 애니메이션
          AsciiCanvasWidget(layers: _composeLayers()),

          // 몬스터 사망 분해 애니메이션 오버레이
          // 몬스터 위치: 캔버스 60열 중 30~48열 (중앙값 41열)
          // Alignment x = (41/60) * 2 - 1 = 0.37
          if (_showDeathAnimation && _deathAnimationMonsterLines != null)
            Align(
              alignment: const Alignment(0.37, 0.0),
              child: AsciiDisintegrateWidget(
                characterLines: _deathAnimationMonsterLines!,
                duration: const Duration(milliseconds: 800),
                textColor: widget.monsterGrade?.displayColorCode != null
                    ? Color(widget.monsterGrade!.displayColorCode!)
                    : null,
                onComplete: _onDeathAnimationComplete,
              ),
            ),
        ],
      ),
    );
  }
}
