import 'dart:async';

import 'package:asciineverdie/src/shared/animation/canvas/ascii_cell.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/character_frames.dart';
import 'package:asciineverdie/src/shared/animation/race_character_frames.dart';
import 'package:flutter/material.dart';

/// 아레나 idle 상태 캐릭터 미리보기 위젯
///
/// 좌측에 도전자, 우측에 상대(좌우 반전)를 idle 상태로 표시
class ArenaIdlePreview extends StatefulWidget {
  const ArenaIdlePreview({
    super.key,
    required this.challengerRaceId,
    required this.opponentRaceId,
  });

  /// 도전자 종족 ID
  final String? challengerRaceId;

  /// 상대 종족 ID
  final String? opponentRaceId;

  @override
  State<ArenaIdlePreview> createState() => _ArenaIdlePreviewState();
}

class _ArenaIdlePreviewState extends State<ArenaIdlePreview> {
  /// 현재 idle 프레임 인덱스 (0~3)
  int _frameIndex = 0;

  /// 애니메이션 타이머
  Timer? _timer;

  /// 레이어 버전 (변경 감지용)
  int _layerVersion = 0;

  /// 캔버스 크기
  static const int _gridWidth = 32;
  static const int _gridHeight = 5;

  /// 캐릭터 위치
  static const int _leftCharX = 4;
  static const int _rightCharX = 22;
  static const int _charY = 1; // 상단 여백

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

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

  void _startAnimation() {
    // 200ms마다 프레임 업데이트 (원본 틱 속도)
    _timer = Timer.periodic(const Duration(milliseconds: 200), (_) {
      setState(() {
        _frameIndex = (_frameIndex + 1) % 4;
        _layerVersion++;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final layers = _composeLayers();

    return SizedBox(
      height: 60,
      child: AsciiCanvasWidget(
        layers: layers,
        gridWidth: _gridWidth,
        gridHeight: _gridHeight,
        backgroundOpacity: 0.3,
        isAnimating: true,
        layerVersion: _layerVersion,
      ),
    );
  }

  /// 레이어 합성
  List<AsciiLayer> _composeLayers() {
    final layers = <AsciiLayer>[];

    // 도전자 캐릭터 (좌측, 정방향)
    final challengerLayer = _createCharacterLayer(
      widget.challengerRaceId,
      _leftCharX,
      mirrored: false,
    );
    layers.add(challengerLayer);

    // 상대 캐릭터 (우측, 좌우 반전)
    final opponentLayer = _createCharacterLayer(
      widget.opponentRaceId,
      _rightCharX,
      mirrored: true,
    );
    layers.add(opponentLayer);

    return layers;
  }

  /// 캐릭터 레이어 생성
  AsciiLayer _createCharacterLayer(
    String? raceId,
    int xOffset, {
    required bool mirrored,
  }) {
    // 종족별 idle 프레임 조회
    CharacterFrame frame;
    if (raceId != null && raceId.isNotEmpty) {
      final raceData = RaceCharacterFrames.get(raceId);
      if (raceData != null) {
        frame = raceData.idle[_frameIndex % raceData.idle.length];
      } else {
        frame = getCharacterFrame(BattlePhase.idle, _frameIndex);
      }
    } else {
      frame = getCharacterFrame(BattlePhase.idle, _frameIndex);
    }

    // 미러링 적용
    final lines = mirrored ? _mirrorLines(frame.lines) : frame.lines;

    // 셀 변환
    final cells = _spriteToCells(lines);

    return AsciiLayer(
      cells: cells,
      zIndex: 1,
      offsetX: xOffset,
      offsetY: _charY,
    );
  }

  /// 문자열 좌우 반전
  List<String> _mirrorLines(List<String> lines) {
    return lines.map((line) {
      final chars = line.split('');
      final mirrored = chars.reversed.map(_mirrorChar).toList();
      return mirrored.join();
    }).toList();
  }

  /// 개별 문자 미러링 (방향성 문자 변환)
  String _mirrorChar(String char) {
    return switch (char) {
      '/' => r'\',
      r'\' => '/',
      '(' => ')',
      ')' => '(',
      '[' => ']',
      ']' => '[',
      '{' => '}',
      '}' => '{',
      '<' => '>',
      '>' => '<',
      '┘' => '└',
      '└' => '┘',
      '┐' => '┌',
      '┌' => '┐',
      'λ' => 'λ', // 대칭
      _ => char,
    };
  }

  /// 문자열 스프라이트를 AsciiCell 2D 배열로 변환
  List<List<AsciiCell>> _spriteToCells(List<String> lines) {
    return lines.map((line) {
      return line.split('').map(AsciiCell.fromChar).toList();
    }).toList();
  }
}
