import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'package:service_api/service_api.dart';
import 'package:feature_common/feature_common.dart'; 

import '../widgets/number_pad.dart';
import '../widgets/sudoku_board.dart';
import '../models/game_level.dart';

class GameScreen extends StatefulWidget {
  final SudokuGameDto gameData;
  final String themeName;
  final String userId;
  final String? userName;
  final int levelIndex;

  const GameScreen({
    super.key,
    required this.gameData,
    required this.themeName,
    required this.userId,
    required this.userName,
    required this.levelIndex,
  });

  @override
  State<GameScreen> createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> {
  final PuzzleService _puzzleService = PuzzleService();
  final IdentityService _identityService = IdentityService();
  
  late final GameLevel currentLevel;
  late final int blockSize;
  late final int gridSize;
  late final SudokuTheme activeTheme;

  late List<int> puzzleCells;
  late List<int> solutionCells;
  late List<int> originalCells;

  int? selectedIndex;
  int score = 5;
  int secondsElapsed = 0;
  Timer? timer;
  int? selectedNumberPad;
  Set<int> incorrectCells = {};
  bool isValidating = false;
  
  late final TransformationController _transformationController;

  // ( ... _charToInt, _intToChar, initState, dispose, startTimer ... )
  // ( ... onCellTapped, _checkIfBoardIsFull, onNumberTapped, onUndoTapped ... )
  // ( ... onHintTapped, _onRestartGameTapped, _onQuitGameTapped, _resetBoardZoom ... )
  int _charToInt(String char) {
    if (char == '0') return 0;
    if (char.codeUnitAt(0) >= '1'.codeUnitAt(0) && char.codeUnitAt(0) <= '9'.codeUnitAt(0)) {
      return int.parse(char);
    }
    if (char.codeUnitAt(0) >= 'A'.codeUnitAt(0) && char.codeUnitAt(0) <= 'Z'.codeUnitAt(0)) {
      return char.codeUnitAt(0) - 'A'.codeUnitAt(0) + 10;
    }
    return -1;
  }
  String _intToChar(int num) {
    if (num == 0) return '0';
    if (num >= 1 && num <= 9) return num.toString();
    if (num >= 10 && num <= 35) return String.fromCharCode('A'.codeUnitAt(0) + (num - 10));
    return '?';
  }
  @override
  void initState() {
    super.initState();
    currentLevel = AppLevels.getLevel(widget.levelIndex);
    blockSize = currentLevel.blockSize;
    gridSize = blockSize * blockSize;
    _transformationController = TransformationController();
    String themeForThisGame = widget.themeName;
    bool isEasyMode = currentLevel.isSequentialNumbers || currentLevel.isSequentialLetters;
    if (currentLevel.isSequentialNumbers) {
      themeForThisGame = AppThemes.numbers;
    } else if (currentLevel.isSequentialLetters) {
      themeForThisGame = AppThemes.letters;
    }
    activeTheme = AppThemes.buildGameTheme(themeForThisGame, gridSize, isEasyMode: isEasyMode);
    puzzleCells = widget.gameData.question.split('').map(_charToInt).toList();
    solutionCells = widget.gameData.solution.split('').map(_charToInt).toList();
    originalCells = widget.gameData.question.split('').map(_charToInt).toList();
    startTimer();
  }
  @override
  void dispose() {
    timer?.cancel();
    _transformationController.dispose();
    super.dispose();
  }
  void startTimer() {
    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() { secondsElapsed++; });
    });
  }
  void onCellTapped(int index) {
    if (originalCells[index] == 0) {
      if (incorrectCells.isNotEmpty && !incorrectCells.contains(index)) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('틀린 값을 먼저 수정해주세요. (되돌리기 ↩)'), duration: Duration(seconds: 1)),
        );
        return;
      }
      setState(() {
        selectedIndex = index;
        if (selectedNumberPad != null) {
          final int numberValue = selectedNumberPad!;
          puzzleCells[index] = numberValue;
          if (numberValue != solutionCells[index]) {
            if (!incorrectCells.contains(index)) {
              if (score > 0) { score--; }
              incorrectCells.add(index);
            }
          } else {
            incorrectCells.remove(index);
          }
          _checkIfBoardIsFull();
        }
      });
    }
  }
  void _checkIfBoardIsFull() {
    if (!puzzleCells.contains(0) && !isValidating) {
      _validateGame();
    }
  }
  void onNumberTapped(int numberValue) {
    setState(() {
      if (selectedNumberPad == numberValue) {
        selectedNumberPad = null;
      } else {
        selectedNumberPad = numberValue;
      }
    });
  }
  void onUndoTapped() {
    if (incorrectCells.isNotEmpty) {
      int errorIndex = incorrectCells.first;
      setState(() {
        puzzleCells[errorIndex] = 0;
        incorrectCells.remove(errorIndex);
        selectedIndex = errorIndex;
      });
    } 
    else if (selectedIndex != null && originalCells[selectedIndex!] == 0) {
      setState(() { puzzleCells[selectedIndex!] = 0; });
    }
  }
  void onHintTapped() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('힌트 기능은 준비 중입니다.')),
    );
  }
  void _onRestartGameTapped() {
    setState(() {
      puzzleCells = originalCells.toList();
      incorrectCells.clear();
      selectedIndex = null;
      selectedNumberPad = null;
      score = 5;
      _resetBoardZoom();
      timer?.cancel();
      secondsElapsed = 0;
      startTimer();
    });
  }
  void _onQuitGameTapped() {
    Navigator.of(context).pop();
  }
  void _resetBoardZoom() {
    _transformationController.value = Matrix4.identity();
  }

  /// 🔽 [수정] _validateGame (Navigation 로직 변경)
  Future<void> _validateGame() async {
    if (isValidating) return;
    setState(() { isValidating = true; });
    
    timer?.cancel();
    String currentAnswer = puzzleCells.map(_intToChar).join('');
    
    try {
      final bool result = await _puzzleService.validateSolution(
        widget.gameData.puzzleId, 
        currentAnswer,
      );

      if (result) {
        if(mounted) {
          // 1. 점수 포맷터 정의
          String formatSudokuScore(int primary, int? secondary) {
            final min = (primary ~/ 60).toString().padLeft(2, '0');
            final sec = (primary % 60).toString().padLeft(2, '0');
            final time = '$min:$sec';
            int displayScore = 5 - (secondary ?? 5);
            return '$time (Score: $displayScore)';
          }

          // 2. 레벨 저장 콜백 정의
          Future<void> saveSudokuProgress(String playerName) async {
            final int currentMaxLevel = await _identityService.getMaxUnlockedLevel();
            if (currentMaxLevel < 99) {
              if (widget.levelIndex >= currentMaxLevel) {
                int nextLevel = widget.levelIndex + 1;
                if (nextLevel > AppLevels.allLevels.length) {
                  await _identityService.saveMaxUnlockedLevel(99);
                } else {
                  await _identityService.saveMaxUnlockedLevel(nextLevel);
                }
              }
            }
          }

          // 3. [수정] 'pushReplacement' 대신 'await push' 사용
          await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => GameCompletionScreen(
                args: GameResultArgs(
                  gameType: 'SUDOKU',
                  contextId: currentLevel.contextId,
                  primaryScore: secondsElapsed,
                  secondaryScore: (5 - score),
                  userId: widget.userId,
                  userName: widget.userName,
                  scoreFormatter: formatSudokuScore,
                  onProgressSave: saveSudokuProgress,
                  // ❌ onScreenClose 제거
                ),
              ),
            ),
          );

          // 4. [추가] 랭킹 화면에서 돌아오면, 게임 화면(self)을 닫고 로비로 돌아감
          if (mounted && Navigator.canPop(context)) {
            Navigator.pop(context);
          }
        }
      } else {
        if(mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('🤔 틀린 부분이 있습니다.')),
          );
        }
        startTimer();
      }
    } catch (e) {
      if(mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('오류: $e')),
        );
      }
      startTimer();
    } finally {
      if(mounted) {
        setState(() { isValidating = false; });
      }
    }
  }

  // ( ... build, _buildPortraitLayout, _buildLandscapeLayout ... )
  // ( ... _buildGameInfoWidget, _buildSudokuBoardWidget, _buildControlPanelWidget ... )
  // ( ... 이 메서드들은 모두 동일합니다 ... )
  @override
  Widget build(BuildContext context) {
    context.watch<ThemeNotifier>();
    String formattedTime = '${(secondsElapsed ~/ 60).toString().padLeft(2, '0')}:${(secondsElapsed % 60).toString().padLeft(2, '0')}';
    final Map<int, int> numberCounts = {};
    for (int i = 1; i <= gridSize; i++) { numberCounts[i] = 0; }
    for (int cellValue in puzzleCells) {
      if (cellValue > 0) {
        numberCounts[cellValue] = (numberCounts[cellValue] ?? 0) + 1;
      }
    }
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              child: LayoutBuilder(
                builder: (context, constraints) {
                  bool isLandscape = constraints.maxWidth > constraints.maxHeight;
                  if (isLandscape) {
                    return _buildLandscapeLayout(context, numberCounts, constraints, formattedTime);
                  } else {
                    return _buildPortraitLayout(context, numberCounts, constraints, formattedTime);
                  }
                },
              ),
            ),
            const AdBannerWidget(),
          ],
        ),
      ),
    );
  }
  Widget _buildPortraitLayout(BuildContext context, Map<int, int> numberCounts, BoxConstraints constraints, String formattedTime) {
    final double boardWidth = (constraints.maxWidth > 600) ? 600 : constraints.maxWidth;
    return Center(
      child: ConstrainedBox(
        constraints: BoxConstraints(maxWidth: boardWidth),
        child: Column(
          children: [
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0),
              child: _buildGameInfoWidget(formattedTime),
            ),
            Expanded(
              child: Center(
                child: SingleChildScrollView(
                  child: Padding(
                    padding: const EdgeInsets.symmetric(vertical: 16.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        _buildSudokuBoardWidget(),
                        const SizedBox(height: 15),
                        Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 16.0),
                          child: _buildControlPanelWidget(context, numberCounts, isLandscape: false, boardWidth: boardWidth),
                        ), 
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
  Widget _buildLandscapeLayout(BuildContext context, Map<int, int> numberCounts, BoxConstraints constraints, String formattedTime) {
    const double infoBarHeight = 60.0;
    double boardWidth = constraints.maxHeight - infoBarHeight - 32.0; 
    double controlPanelWidth;
    const double numberPadScaleRatio = 0.6;
    double padWidth = boardWidth * numberPadScaleRatio;
    if (padWidth < 200) padWidth = 200;
    if (padWidth > 350) padWidth = 350;
    controlPanelWidth = padWidth + 100;
    double totalWidth = boardWidth + controlPanelWidth + 16.0;
    if (totalWidth > (constraints.maxWidth - 32.0)) {
      double scale = (constraints.maxWidth - 32.0) / totalWidth;
      boardWidth *= scale;
      controlPanelWidth *= scale;
    }
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        children: [
          _buildGameInfoWidget(formattedTime),
          Expanded(
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                SizedBox(
                  width: boardWidth,
                  child: _buildSudokuBoardWidget(),
                ),
                const SizedBox(width: 16),
                SizedBox(
                  width: controlPanelWidth,
                  child: SingleChildScrollView(
                    child: Column(
                      children: [
                        _buildControlPanelWidget(context, numberCounts, isLandscape: true, boardWidth: boardWidth),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
  Widget _buildGameInfoWidget(String formattedTime) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Text('SCORE: $score', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
        Text(formattedTime, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
      ],
    );
  }
  Widget _buildSudokuBoardWidget() {
    return GestureDetector(
      onLongPress: _resetBoardZoom,
      child: InteractiveViewer(
        transformationController: _transformationController,
        boundaryMargin: const EdgeInsets.all(20.0),
        minScale: 1.0,
        maxScale: 2.5,
        child: SudokuBoard(
          blockSize: blockSize,
          theme: activeTheme,
          cells: puzzleCells,
          originalCells: originalCells,
          selectedIndex: selectedIndex,
          selectedNumberPad: selectedNumberPad,
          incorrectCells: incorrectCells,
          onCellTapped: onCellTapped,
        ),
      ),
    );
  }
  Widget _buildControlPanelWidget(BuildContext context, Map<int, int> numberCounts, {required bool isLandscape, required double boardWidth}) {
    final ThemeData themeData = Theme.of(context);
    const double numberPadScaleRatio = 0.6;
    double? padMaxWidth;
    if (!isLandscape) {
        padMaxWidth = boardWidth * numberPadScaleRatio;
    } else {
        padMaxWidth = boardWidth * numberPadScaleRatio;
        if (padMaxWidth < 200) padMaxWidth = 200;
    }
    Widget numberPadGrid = ConstrainedBox(
      constraints: BoxConstraints(maxWidth: padMaxWidth ?? double.infinity),
      child: NumberPad(
        blockSize: blockSize,
        theme: activeTheme,
        numberCounts: numberCounts,
        selectedNumber: selectedNumberPad, 
        onNumberTapped: onNumberTapped,
        isLandscape: isLandscape,
      ),
    );
    Widget leftButtons = Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          icon: Icon(Icons.close, color: themeData.colorScheme.error, size: 30),
          onPressed: _onQuitGameTapped,
          tooltip: "게임 종료",
        ),
        IconButton(
          icon: Icon(Icons.refresh, color: themeData.colorScheme.secondary, size: 30),
          onPressed: _onRestartGameTapped,
          tooltip: "다시하기",
        ),
      ],
    );
    Widget rightButtons = Column(
      mainAxisSize: MainAxisSize.min, 
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          onPressed: onHintTapped,
          icon: Icon(Icons.lightbulb_outline, color: themeData.colorScheme.secondary, size: 30),
          tooltip: "힌트",
        ),
        IconButton(
          onPressed: onUndoTapped,
          icon: Icon(Icons.undo, color: themeData.colorScheme.error, size: 30),
          tooltip: "되돌리기",
        ),
      ],
    );
    if (isLandscape) {
      return Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          numberPadGrid,
          const SizedBox(height: 10),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              leftButtons,
              rightButtons
            ],
          )
        ],
      );
    } else {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          leftButtons,
          Expanded(child: numberPadGrid),
          rightButtons,
        ],
      );
    }
  }
}