import 'package:cabo_counter/core/constants.dart';
import 'package:cabo_counter/core/custom_theme.dart';
import 'package:cabo_counter/data/db/database.dart';
import 'package:cabo_counter/data/dto/game_manager.dart';
import 'package:cabo_counter/data/dto/game_session.dart';
import 'package:cabo_counter/data/dto/player.dart';
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
import 'package:cabo_counter/presentation/views/home/active_game/active_game_view.dart';
import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart';
import 'package:cabo_counter/presentation/widgets/custom_button.dart';
import 'package:cabo_counter/services/config_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';

enum CreateStatus {
  noGameTitle,
  noModeSelected,
  minPlayers,
  maxPlayers,
  noPlayerName,
}

/// A view for creating a new game session in the Cabo Counter app.
///
/// The [CreateGameView] allows users to input a game title, select a game mode,
/// add and reorder player names, and validate all required fields before
/// starting a new game. It provides feedback dialogs for missing or invalid
/// input and navigates to the active game view upon successful creation.
class CreateGameView extends StatefulWidget {
  final GameMode gameMode;
  final String? gameTitle;
  final List<String>? players;

  const CreateGameView({
    super.key,
    this.gameTitle,
    this.players,
    required this.gameMode,
  });

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

class _CreateGameViewState extends State<CreateGameView> {
  final TextEditingController _gameTitleTextController =
      TextEditingController();

  /// List of text controllers for player names.
  final List<TextEditingController> _playerNameTextControllers = [
    TextEditingController()
  ];

  /// List of focus nodes for player name text fields.
  final List<FocusNode> _playerNameFocusNodes = [FocusNode()];

  /// Maximum number of players allowed in the game.
  final int maxPlayers = 5;

  /// Factor to adjust the view length when the keyboard is visible.
  final double keyboardHeightAdjustmentFactor = 0.75;

  /// Variable to hold the selected game mode.
  late GameMode gameMode;

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

    gameMode = widget.gameMode;

    _gameTitleTextController.text = widget.gameTitle ?? '';

    if (widget.players != null) {
      _playerNameTextControllers.clear();
      for (var player in widget.players!) {
        _playerNameTextControllers.add(TextEditingController(text: player));
        _playerNameFocusNodes.add(FocusNode());
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
        canPop: false,
        onPopInvokedWithResult: (bool didPop, dynamic result) async {
          if (!didPop) {
            await _keyboardDelay();
            if (context.mounted) Navigator.pop(context);
          }
        },
        child: CupertinoPageScaffold(
            resizeToAvoidBottomInset: false,
            navigationBar: CupertinoNavigationBar(
              previousPageTitle: AppLocalizations.of(context).games,
              middle: Text(AppLocalizations.of(context).new_game),
            ),
            child: SafeArea(
                child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
                    child: Text(
                      AppLocalizations.of(context).game,
                      style: CustomTheme.rowTitle,
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
                    child: CupertinoTextField(
                      decoration: const BoxDecoration(),
                      maxLength: 20,
                      prefix: Text(AppLocalizations.of(context).name),
                      textAlign: TextAlign.right,
                      placeholder: AppLocalizations.of(context).game_title,
                      controller: _gameTitleTextController,
                      onSubmitted: (_) {
                        _playerNameFocusNodes.isNotEmpty
                            ? _playerNameFocusNodes[0].requestFocus()
                            : FocusScope.of(context).unfocus();
                      },
                      textInputAction: _playerNameFocusNodes.isNotEmpty
                          ? TextInputAction.next
                          : TextInputAction.done,
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
                    child: CupertinoTextField(
                      decoration: const BoxDecoration(),
                      readOnly: true,
                      prefix: Text(AppLocalizations.of(context).mode),
                      suffix: Row(
                        children: [
                          _getDisplayedGameMode(),
                          const SizedBox(width: 3),
                          const CupertinoListTileChevron(),
                        ],
                      ),
                      onTap: () async {
                        await _keyboardDelay();

                        if (context.mounted) {
                          final selectedMode = await Navigator.push(
                            context,
                            CupertinoPageRoute(
                              builder: (context) => ModeSelectionMenu(
                                pointLimit: ConfigService.getPointLimit(),
                                showDeselection: false,
                              ),
                            ),
                          );

                          setState(() {
                            gameMode = selectedMode ?? gameMode;
                          });
                        }
                      },
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
                    child: Text(
                      AppLocalizations.of(context).players,
                      style: CustomTheme.rowTitle,
                    ),
                  ),
                  ReorderableListView.builder(
                      shrinkWrap: true,
                      physics: const BouncingScrollPhysics(),
                      padding: const EdgeInsets.all(8),
                      itemCount: _playerNameTextControllers.length,
                      onReorder: (oldIndex, newIndex) {
                        setState(() {
                          if (oldIndex < _playerNameTextControllers.length &&
                              newIndex <= _playerNameTextControllers.length) {
                            if (newIndex > oldIndex) newIndex--;
                            final item =
                                _playerNameTextControllers.removeAt(oldIndex);
                            _playerNameTextControllers.insert(newIndex, item);
                          }
                        });
                      },
                      itemBuilder: (context, index) {
                        return Padding(
                          key: ValueKey(index),
                          padding: const EdgeInsets.symmetric(vertical: 8.0),
                          child: Row(
                            children: [
                              CupertinoButton(
                                padding: EdgeInsets.zero,
                                child: Icon(
                                  CupertinoIcons.minus_circle_fill,
                                  color: CustomTheme.red,
                                  size: 25,
                                ),
                                onPressed: () {
                                  setState(() {
                                    _playerNameTextControllers[index].dispose();
                                    _playerNameTextControllers.removeAt(index);
                                  });
                                },
                              ),
                              Expanded(
                                child: CupertinoTextField(
                                  controller: _playerNameTextControllers[index],
                                  focusNode: _playerNameFocusNodes[index],
                                  maxLength: 12,
                                  placeholder:
                                      '${AppLocalizations.of(context).player} ${index + 1}',
                                  padding: const EdgeInsets.all(12),
                                  decoration: const BoxDecoration(),
                                  textInputAction: index + 1 <
                                          _playerNameTextControllers.length
                                      ? TextInputAction.next
                                      : TextInputAction.done,
                                  onSubmitted: (_) {
                                    if (index + 1 <
                                        _playerNameFocusNodes.length) {
                                      _playerNameFocusNodes[index + 1]
                                          .requestFocus();
                                    } else {
                                      FocusScope.of(context).unfocus();
                                    }
                                  },
                                ),
                              ),
                              AnimatedOpacity(
                                opacity: _playerNameTextControllers.length > 1
                                    ? 1.0
                                    : 0.0,
                                duration: const Duration(
                                    milliseconds: Constants.kFadeInDuration),
                                child: Padding(
                                  padding: const EdgeInsets.only(right: 8.0),
                                  child: ReorderableDragStartListener(
                                    index: index,
                                    child: const Icon(
                                      CupertinoIcons.line_horizontal_3,
                                      color: CupertinoColors.systemGrey,
                                    ),
                                  ),
                                ),
                              )
                            ],
                          ),
                        );
                      }),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(8, 0, 8, 50),
                    child: Stack(
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.start,
                          children: [
                            CupertinoButton(
                              padding: EdgeInsets.zero,
                              onPressed: null,
                              child: Icon(
                                CupertinoIcons.plus_circle_fill,
                                color: CustomTheme.primaryColor,
                                size: 25,
                              ),
                            ),
                          ],
                        ),
                        Center(
                          child: CupertinoButton(
                            padding: const EdgeInsets.symmetric(horizontal: 0),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                Expanded(
                                  child: Center(
                                    child: Text(
                                      AppLocalizations.of(context).add_player,
                                      style: TextStyle(
                                          color: CustomTheme.primaryColor),
                                    ),
                                  ),
                                ),
                              ],
                            ),
                            onPressed: () {
                              if (_playerNameTextControllers.length <
                                  maxPlayers) {
                                setState(() {
                                  _playerNameTextControllers
                                      .add(TextEditingController());
                                  _playerNameFocusNodes.add(FocusNode());
                                });
                                WidgetsBinding.instance
                                    .addPostFrameCallback((_) {
                                  _playerNameFocusNodes.last.requestFocus();
                                });
                              } else {
                                _showFeedbackDialog(CreateStatus.maxPlayers);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(0, 0, 0, 50),
                    child: Center(
                      child: CustomButton(
                        child: Text(
                          AppLocalizations.of(context).create_game,
                          style: TextStyle(
                            color: CustomTheme.primaryColor,
                          ),
                        ),
                        onPressed: () async {
                          await _keyboardDelay();
                          _checkAllGameAttributes();
                        },
                      ),
                    ),
                  ),
                  KeyboardVisibilityBuilder(builder: (context, visible) {
                    if (visible) {
                      return SizedBox(
                        height: MediaQuery.of(context).viewInsets.bottom *
                            keyboardHeightAdjustmentFactor,
                      );
                    } else {
                      return const SizedBox.shrink();
                    }
                  })
                ],
              ),
            ))));
  }

  /// Returns a widget that displays the currently selected game mode in the View.
  Text _getDisplayedGameMode() {
    if (gameMode == GameMode.none) {
      return Text(AppLocalizations.of(context).no_mode_selected);
    } else if (gameMode == GameMode.pointLimit) {
      return Text(
          '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}',
          style: TextStyle(color: CustomTheme.primaryColor));
    } else {
      return Text(AppLocalizations.of(context).unlimited,
          style: TextStyle(color: CustomTheme.primaryColor));
    }
  }

  /// Checks all game attributes before creating a new game.
  /// If any attribute is invalid, it shows a feedback dialog.
  /// If all attributes are valid, it calls the `_createGame` method.
  void _checkAllGameAttributes() {
    if (_gameTitleTextController.text == '') {
      _showFeedbackDialog(CreateStatus.noGameTitle);
      return;
    }

    if (gameMode == GameMode.none) {
      _showFeedbackDialog(CreateStatus.noModeSelected);
      return;
    }

    if (_playerNameTextControllers.length < 2) {
      _showFeedbackDialog(CreateStatus.minPlayers);
      return;
    }

    if (!_everyPlayerHasAName()) {
      _showFeedbackDialog(CreateStatus.noPlayerName);
      return;
    }

    _createGame();
  }

  /// Checks if every player has a name.
  /// Returns true if all players have a name, false otherwise.
  bool _everyPlayerHasAName() {
    for (var controller in _playerNameTextControllers) {
      if (controller.text == '') {
        return false;
      }
    }
    return true;
  }

  /// Displays a feedback dialog based on the [CreateStatus].
  void _showFeedbackDialog(CreateStatus status) {
    final (title, message) = _getDialogContent(status);

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

  /// Returns the title and message for the dialog based on the [CreateStatus].
  (String, String) _getDialogContent(CreateStatus status) {
    switch (status) {
      case CreateStatus.noGameTitle:
        return (
          AppLocalizations.of(context).no_gameTitle_title,
          AppLocalizations.of(context).no_gameTitle_message
        );
      case CreateStatus.noModeSelected:
        return (
          AppLocalizations.of(context).no_mode_title,
          AppLocalizations.of(context).no_mode_message
        );

      case CreateStatus.minPlayers:
        return (
          AppLocalizations.of(context).min_players_title,
          AppLocalizations.of(context).min_players_message
        );
      case CreateStatus.maxPlayers:
        return (
          AppLocalizations.of(context).max_players_title,
          AppLocalizations.of(context).max_players_message
        );
      case CreateStatus.noPlayerName:
        return (
          AppLocalizations.of(context).no_name_title,
          AppLocalizations.of(context).no_name_message
        );
    }
  }

  /// Creates a new gameSession and navigates to the active game view.
  /// This method creates a new gameSession object with the provided attributes in the text fields.
  /// It then adds the game session to the game manager and navigates to the active game view.
  void _createGame() {
    var uuid = const Uuid();
    final String gameId = uuid.v1();

    // Collect player names from the text controllers.
    List<String> playerNames = [];
    for (var controller in _playerNameTextControllers) {
      playerNames.add(controller.text);
    }

    // Create a list of Player objects with unique IDs and the corresponding attributes
    List<Player> playerList = [];
    for (int i = 0; i < playerNames.length; i++) {
      playerList.add(Player(
        playerId: uuid.v1(),
        gameId: gameId,
        name: playerNames[i],
        position: i,
      ));
    }

    bool isPointsLimitEnabled = gameMode == GameMode.pointLimit;

    GameSession gameSession = GameSession(
        id: gameId,
        createdAt: DateTime.now(),
        gameTitle: _gameTitleTextController.text,
        players: playerList,
        pointLimit: ConfigService.getPointLimit(),
        caboPenalty: ConfigService.getCaboPenalty(),
        isPointsLimitEnabled: isPointsLimitEnabled,
        isGameFinished: false);

    final db = Provider.of<AppDatabase>(context, listen: false);
    gameManager.addGameSession(gameSession, db);
    final session = gameManager.getGameSessionById(gameId) ?? gameSession;

    Navigator.pushAndRemoveUntil(
      context,
      CupertinoPageRoute(
          builder: (context) => ActiveGameView(gameSession: session)),
      (Route<dynamic> route) => route.isFirst,
    );
  }

  /// If the keyboard is visible, this method will unfocus the current text field
  /// to prevent the keyboard from interfering with the navigation bar.
  Future<void> _keyboardDelay() async {
    if (!KeyboardVisibilityController().isVisible) {
      return;
    } else {
      FocusScope.of(context).unfocus();
      await Future.delayed(
          const Duration(milliseconds: Constants.kKeyboardDelay));
    }
  }

  @override
  void dispose() {
    _gameTitleTextController.dispose();
    for (var controller in _playerNameTextControllers) {
      controller.dispose();
    }
    for (var focusnode in _playerNameFocusNodes) {
      focusnode.dispose();
    }

    super.dispose();
  }
}
