import 'package:cabo_counter/core/custom_theme.dart';
import 'package:cabo_counter/data/game_session.dart';
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
import 'package:cabo_counter/services/local_storage_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

class RoundView extends StatefulWidget {
  final GameSession gameSession;
  final int roundNumber;
  const RoundView(
      {super.key, required this.roundNumber, required this.gameSession});

  @override
  // ignore: library_private_types_in_public_api
  _RoundViewState createState() => _RoundViewState();
}

class _RoundViewState extends State<RoundView> {
  /// The current game session.
  late GameSession gameSession = widget.gameSession;

  /// Index of the player who said CABO.
  int _caboPlayerIndex = 0;

  /// Index of the player who has Kamikaze.
  /// Default is null (no Kamikaze player).
  int? _kamikazePlayerIndex;

  /// List of text controllers for the score text fields.
  late final List<TextEditingController> _scoreControllerList = List.generate(
    widget.gameSession.players.length,
    (index) => TextEditingController(),
  );

  /// List of focus nodes for the score text fields.
  late final List<FocusNode> _focusNodeList = List.generate(
    widget.gameSession.players.length,
    (index) => FocusNode(),
  );

  @override
  void initState() {
    print('=== Runde ${widget.roundNumber} geöffnet ===');
    if (widget.roundNumber < widget.gameSession.roundNumber ||
        widget.gameSession.isGameFinished == true) {
      print(
          'Diese wurde bereits gespielt, deshalb werden die alten Punktestaende angezeigt');

      // If the current round has already been played, the text fields
      // are filled with the scores from this round
      for (int i = 0; i < _scoreControllerList.length; i++) {
        _scoreControllerList[i].text =
            gameSession.roundList[widget.roundNumber - 1].scores[i].toString();
      }
      _caboPlayerIndex =
          gameSession.roundList[widget.roundNumber - 1].caboPlayerIndex;
      _kamikazePlayerIndex =
          gameSession.roundList[widget.roundNumber - 1].kamikazePlayerIndex;
    }

    super.initState();
  }

  @override
  @override
  Widget build(BuildContext context) {
    final bottomInset = MediaQuery.of(context).viewInsets.bottom;
    final rotatedPlayers = _getRotatedPlayers();
    final originalIndices = _getOriginalIndices();

    return CupertinoPageScaffold(
      resizeToAvoidBottomInset: false,
      navigationBar: CupertinoNavigationBar(
          transitionBetweenRoutes: true,
          leading: CupertinoButton(
            padding: EdgeInsets.zero,
            onPressed: () => {
              LocalStorageService.saveGameSessions(),
              Navigator.pop(context)
            },
            child: Text(AppLocalizations.of(context).cancel),
          ),
          middle: Text(AppLocalizations.of(context).results),
          trailing: Visibility(
              visible: widget.gameSession.isGameFinished,
              child: const Icon(
                CupertinoIcons.lock,
                size: 25,
              ))),
      child: Stack(
        children: [
          Positioned.fill(
            child: SingleChildScrollView(
              padding: EdgeInsets.only(bottom: 100 + bottomInset),
              child: SafeArea(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const SizedBox(height: 40),
                    Text(
                        '${AppLocalizations.of(context).round} ${widget.roundNumber}',
                        style: CustomTheme.roundTitle),
                    const SizedBox(height: 10),
                    Text(
                      AppLocalizations.of(context).who_said_cabo,
                      style: const TextStyle(fontWeight: FontWeight.bold),
                    ),
                    Padding(
                      padding: EdgeInsets.symmetric(
                        horizontal:
                            widget.gameSession.players.length > 3 ? 5 : 20,
                        vertical: 10,
                      ),
                      child: SizedBox(
                        height: 60,
                        child: CupertinoSegmentedControl<int>(
                          unselectedColor:
                              CustomTheme.mainElementBackgroundColor,
                          selectedColor: CustomTheme.primaryColor,
                          groupValue: _caboPlayerIndex,
                          children: Map.fromEntries(widget.gameSession.players
                              .asMap()
                              .entries
                              .map((entry) {
                            final index = entry.key;
                            final name = entry.value;
                            return MapEntry(
                              index,
                              Padding(
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 6,
                                  vertical: 8,
                                ),
                                child: FittedBox(
                                  fit: BoxFit.scaleDown,
                                  child: Text(
                                    name,
                                    textAlign: TextAlign.center,
                                    maxLines: 1,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                ),
                              ),
                            );
                          })),
                          onValueChanged: (value) {
                            setState(() {
                              _caboPlayerIndex = value;
                            });
                          },
                        ),
                      ),
                    ),
                    ListView.builder(
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(),
                      itemCount: rotatedPlayers.length,
                      itemBuilder: (context, index) {
                        final originalIndex = originalIndices[index];
                        final name = rotatedPlayers[index];
                        bool shouldShowMedal =
                            index == 0 && widget.roundNumber > 1;
                        return Padding(
                          padding: const EdgeInsets.symmetric(
                              vertical: 10, horizontal: 20),
                          child: ClipRRect(
                            borderRadius: BorderRadius.circular(12),
                            child: CupertinoListTile(
                              backgroundColor: CustomTheme.playerTileColor,
                              title: Row(children: [
                                Expanded(
                                    child: Row(children: [
                                  Text(
                                    name,
                                    overflow: TextOverflow.ellipsis,
                                  ),
                                  Visibility(
                                    visible: shouldShowMedal,
                                    child: const SizedBox(width: 10),
                                  ),
                                  Visibility(
                                      visible: shouldShowMedal,
                                      child: const Icon(FontAwesomeIcons.crown,
                                          size: 15))
                                ]))
                              ]),
                              subtitle: Text(
                                  '${widget.gameSession.playerScores[originalIndex]}'
                                  ' ${AppLocalizations.of(context).points}'),
                              trailing: SizedBox(
                                width: 100,
                                child: CupertinoTextField(
                                  maxLength: 3,
                                  focusNode: _focusNodeList[originalIndex],
                                  keyboardType:
                                      const TextInputType.numberWithOptions(
                                    signed: true,
                                    decimal: false,
                                  ),
                                  inputFormatters: [
                                    FilteringTextInputFormatter.digitsOnly,
                                  ],
                                  textInputAction: index ==
                                          widget.gameSession.players.length - 1
                                      ? TextInputAction.done
                                      : TextInputAction.next,
                                  controller:
                                      _scoreControllerList[originalIndex],
                                  placeholder:
                                      AppLocalizations.of(context).points,
                                  textAlign: TextAlign.center,
                                  onSubmitted: (_) =>
                                      _focusNextTextfield(originalIndex),
                                  onChanged: (_) => setState(() {}),
                                ),
                              ),
                            ),
                          ),
                        );
                      },
                    ),
                    Padding(
                      padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
                      child: Center(
                        heightFactor: 1,
                        child: CupertinoButton(
                          sizeStyle: CupertinoButtonSize.medium,
                          borderRadius: BorderRadius.circular(12),
                          color: CustomTheme.buttonBackgroundColor,
                          onPressed: () async {
                            if (await _showKamikazeSheet(context)) {
                              if (!context.mounted) return;
                              _endOfRoundNavigation(context, true);
                            }
                          },
                          child: Text(
                            AppLocalizations.of(context).kamikaze,
                            style: const TextStyle(
                              color: CupertinoColors.destructiveRed,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          Positioned(
            left: 0,
            right: 0,
            bottom: bottomInset,
            child: KeyboardVisibilityBuilder(builder: (context, visible) {
              if (!visible) {
                return Container(
                  height: 80,
                  padding: const EdgeInsets.only(bottom: 20),
                  color: CustomTheme.mainElementBackgroundColor,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      CupertinoButton(
                        onPressed: _areRoundInputsValid()
                            ? () {
                                _endOfRoundNavigation(context, false);
                              }
                            : null,
                        child: Text(AppLocalizations.of(context).done),
                      ),
                      if (!widget.gameSession.isGameFinished)
                        CupertinoButton(
                          onPressed: _areRoundInputsValid()
                              ? () {
                                  _endOfRoundNavigation(context, true);
                                }
                              : null,
                          child: Text(AppLocalizations.of(context).next_round),
                        ),
                    ],
                  ),
                );
              } else {
                return const SizedBox.shrink();
              }
            }),
          )
        ],
      ),
    );
  }

  /// Gets the index of the player who won the previous round.
  int _getPreviousRoundWinnerIndex() {
    if (widget.roundNumber == 1) {
      return 0; // If it's the first round, there's no previous round, so return 0.
    }

    final previousRound = widget.gameSession.roundList[widget.roundNumber - 2];
    final scores = previousRound.scoreUpdates;

    // Find the index of the player with the minimum score
    int minScore = scores[0];
    int winnerIndex = 0;

    // Iterate through the scores to find the player with the minimum score
    for (int i = 1; i < scores.length; i++) {
      if (scores[i] < minScore) {
        minScore = scores[i];
        winnerIndex = i;
      }
    }

    return winnerIndex;
  }

  /// Rotates the players list based on the previous round's winner.
  List<String> _getRotatedPlayers() {
    final winnerIndex = _getPreviousRoundWinnerIndex();
    return [
      widget.gameSession.players[winnerIndex],
      ...widget.gameSession.players.sublist(winnerIndex + 1),
      ...widget.gameSession.players.sublist(0, winnerIndex)
    ];
  }

  /// Gets the original indices of the players by recalculating it from the rotated list.
  List<int> _getOriginalIndices() {
    final winnerIndex = _getPreviousRoundWinnerIndex();
    return [
      winnerIndex,
      ...List.generate(widget.gameSession.players.length - winnerIndex - 1,
          (i) => winnerIndex + i + 1),
      ...List.generate(winnerIndex, (i) => i)
    ];
  }

  /// Shows a Cupertino action sheet to select the player who has Kamikaze.
  /// It returns true if a player was selected, false if the action was cancelled.
  Future<bool> _showKamikazeSheet(BuildContext context) async {
    return await showCupertinoModalPopup<bool?>(
          context: context,
          builder: (BuildContext context) {
            return CupertinoActionSheet(
              title: Text(AppLocalizations.of(context).kamikaze),
              message: Text(AppLocalizations.of(context).who_has_kamikaze),
              actions: widget.gameSession.players.asMap().entries.map((entry) {
                final index = entry.key;
                final name = entry.value;
                return CupertinoActionSheetAction(
                  onPressed: () {
                    _kamikazePlayerIndex = index;
                    Navigator.pop(context, true);
                  },
                  child: Text(name),
                );
              }).toList(),
              cancelButton: CupertinoActionSheetAction(
                onPressed: () => Navigator.pop(context, false),
                isDestructiveAction: true,
                child: Text(AppLocalizations.of(context).cancel),
              ),
            );
          },
        ) ??
        false;
  }

  /// Focuses the next text field in the list of text fields.
  /// [index] is the index of the current text field.
  void _focusNextTextfield(int index) {
    final originalIndices = _getOriginalIndices();
    final currentPos = originalIndices.indexOf(index);

    if (currentPos < originalIndices.length - 1) {
      FocusScope.of(context)
          .requestFocus(_focusNodeList[originalIndices[currentPos + 1]]);
    } else {
      _focusNodeList[index].unfocus();
    }
  }

  /// Checks if the inputs for the round are valid.
  /// Returns true if the inputs are valid, false otherwise.
  /// Round Inputs are valid if every player has a score or
  /// kamikaze is selected for a player
  bool _areRoundInputsValid() {
    if (_areTextFieldsEmpty() && _kamikazePlayerIndex == null) return false;
    return true;
  }

  /// Checks if any of the text fields for the players points are empty.
  /// Returns true if any of the text fields is empty, false otherwise.
  bool _areTextFieldsEmpty() {
    for (TextEditingController t in _scoreControllerList) {
      if (t.text.isEmpty) {
        return true;
      }
    }
    return false;
  }

  /// Finishes the current round.
  /// It first determines, ifCalls the [_calculateScoredPoints()] method to calculate the points for
  /// every player. If the round is the highest round played in this game,
  /// it expands the player score lists. At the end it updates the score
  /// array for the game.
  List<int> _finishRound() {
    print('====================================');
    print('Runde ${widget.roundNumber} beendet');
    // The shown round is smaller than the newest round
    if (widget.roundNumber < widget.gameSession.roundNumber) {
      print('Da diese Runde bereits gespielt wurde, werden die alten '
          'Punktestaende ueberschrieben');
    }
    if (_kamikazePlayerIndex != null) {
      print('${widget.gameSession.players[_kamikazePlayerIndex!]} hat Kamikaze '
          'und bekommt 0 Punkte');
      print('Alle anderen Spieler bekommen 50 Punkte');
      widget.gameSession
          .applyKamikaze(widget.roundNumber, _kamikazePlayerIndex!);
    } else {
      List<int> roundScores = [];
      for (TextEditingController c in _scoreControllerList) {
        if (c.text.isNotEmpty) roundScores.add(int.parse(c.text));
      }
      widget.gameSession.calculateScoredPoints(
          widget.roundNumber, roundScores, _caboPlayerIndex);
    }
    List<int> bonusPlayers = widget.gameSession.updatePoints();
    if (widget.gameSession.isGameFinished == true) {
      print('Das Spiel ist beendet');
    } else if (widget.roundNumber == widget.gameSession.roundNumber) {
      widget.gameSession.increaseRound();
    }
    return bonusPlayers;
  }

  /// Shows a popup dialog with the information which player received the bonus points.
  Future<void> _showBonusPopup(
      BuildContext context, List<int> bonusPlayers) async {
    int pointLimit = widget.gameSession.pointLimit;
    int bonusPoints = (pointLimit / 2).round();

    String resultText =
        _getBonusPopupMessageString(pointLimit, bonusPoints, bonusPlayers);

    await showCupertinoDialog(
      context: context,
      builder: (context) => CupertinoAlertDialog(
        title: Text(AppLocalizations.of(context).bonus_points_title),
        content: Text(resultText),
        actions: [
          CupertinoDialogAction(
            child: Text(AppLocalizations.of(context).ok),
            onPressed: () => Navigator.of(context).pop(),
          ),
        ],
      ),
    );
  }

  /// Generates the message string for the bonus popup.
  /// It takes the [pointLimit], [bonusPoints] and the list of [bonusPlayers]
  /// and returns a formatted string.
  String _getBonusPopupMessageString(
      int pointLimit, int bonusPoints, List<int> bonusPlayers) {
    List<String> nameList =
        bonusPlayers.map((i) => widget.gameSession.players[i]).toList();
    String resultText = '';
    if (nameList.length == 1) {
      resultText = AppLocalizations.of(context).bonus_points_message(
          nameList.length, nameList.first, pointLimit, bonusPoints);
    } else {
      resultText = nameList.length == 2
          ? '${nameList[0]} & ${nameList[1]}'
          : '${nameList.sublist(0, nameList.length - 1).join(', ')} & ${nameList.last}';
      resultText = AppLocalizations.of(context).bonus_points_message(
        nameList.length,
        resultText,
        pointLimit,
        bonusPoints,
      );
    }
    return resultText;
  }

  /// Handles the navigation for the end of the round.
  /// It checks for bonus players and shows a popup, saves the game session,
  /// and navigates to the next round or back to the previous screen.
  /// It takes the BuildContext [context] and a boolean [navigateToNextRound] to determine
  /// if it should navigate to the next round or not.
  Future<void> _endOfRoundNavigation(
      BuildContext context, bool navigateToNextRound) async {
    List<int> bonusPlayersIndices = _finishRound();
    if (bonusPlayersIndices.isNotEmpty) {
      await _showBonusPopup(context, bonusPlayersIndices);
    }

    LocalStorageService.saveGameSessions();

    if (context.mounted) {
      // If the game is finished, pop the context and return to the previous screen.
      if (widget.gameSession.isGameFinished) {
        Navigator.pop(context);
        return;
      }
      // If navigateToNextRound is false, pop the context and return to the previous screen.
      if (!navigateToNextRound) {
        Navigator.pop(context);
        return;
      }
      // If navigateToNextRound is true and the game isn't finished yet,
      // pop the context and navigate to the next round.
      Navigator.pop(context, widget.roundNumber + 1);
    }
  }

  @override
  void dispose() {
    for (final controller in _scoreControllerList) {
      controller.dispose();
    }
    for (final focusNode in _focusNodeList) {
      focusNode.dispose();
    }
    super.dispose();
  }
}
