using System;
using System.Collections.Generic;
using System.Linq;
using common.GUIUtils;
using Eagle0.Tutorial;
using Net.Eagle0.Eagle.Api;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace eagle {
    public class CommandPanelController : MonoBehaviour {
        public EagleGameController mainController;

        public CommandSelector _selector;
        public CommandSelector Selector {
            get => _selector;
        private
            set {
                if (_selector != value) {
                    if (_selector != null) _selector.Hide();
                    _selector = value;
                    if (_selector != null) _selector.Show();
                }
            }
        }
        public SelectedCommand SelectedCommand => Selector == null ? null : Selector.Command;

        public TMP_Text headerLabel;
        public Button commitCommandButton;
        public TextMeshProUGUI commitButtonText;
        public Button infoButton;
        public IGameModel Model { get; set; }
        public ErrorHandler errorHandler;
        public CommandWarningPanelController commandWarningPanelController;

        private AvailableCommand _availableCommand;
        public AvailableCommand AvailableCommand {
            get => _availableCommand;
        private
            set {
                if (_availableCommand == null || !_availableCommand.Equals(value)) {
                    _availableCommand = value;
                }
            }
        }

        public void RefreshUI() {
            if (Selector != null) { Selector.RefreshUI(); }
        }

        public void UpdateSelectorLayoutMode(LayoutMode mode) {
            if (Selector != null && Selector.CurrentLayoutMode != mode) {
                Selector.CurrentLayoutMode = mode;
                Selector.OnLayoutModeChanged();
            }
        }

        public void SetAvailableCommandAndSelector(AvailableCommand cmd, CommandSelector sel) {
            // Check if command help is currently showing before changing selector
            bool helpWasShowing = IsCommandHelpShowing();

            AvailableCommand = cmd;
            Selector = sel;

            try {
                if (AvailableCommand == null) {
                    Selector = null;
                    headerLabel.text = null;
                    return;
                }

                // Pass layout mode to selector before setting up UI
                Selector.CurrentLayoutMode = mainController.CurrentLayoutMode;
                Selector.UpdateAvailableCommand(Model, AvailableCommand);
                headerLabel.text = Selector.HeaderString;

                // If help was showing for previous command, show help for new command
                if (helpWasShowing) { ShowCurrentCommandHelp(); }
            } catch (Exception e) { errorHandler.Add(e); }
        }

        /// <summary>
        /// Returns true if a command help panel is currently showing.
        /// </summary>
        private bool IsCommandHelpShowing() {
            var activeId = TutorialManager.Instance?.ActiveSequenceId;
            return activeId != null && activeId.StartsWith("command_");
        }

        /// <summary>
        /// Shows help for the current command (used when switching commands while help is open).
        /// </summary>
        private void ShowCurrentCommandHelp() {
            if (Selector == null) return;
            string tutorialId = GetCurrentCommandTutorialId();
            if (tutorialId != null) { TutorialManager.Instance?.ShowCommandHelp(tutorialId); }
        }

        /// <summary>
        /// Gets the tutorial ID for the current command.
        /// </summary>
        private string GetCurrentCommandTutorialId() {
            if (Selector == null) return null;

            var commandName = Selector.CommandType.ToString();
            if (commandName.EndsWith("Command")) {
                commandName = commandName.Substring(0, commandName.Length - "Command".Length);
            }
            var snakeCase = System.Text.RegularExpressions.Regex.Replace(
                    commandName,
                    "([a-z])([A-Z])",
                    "$1_$2");
            return $"command_{snakeCase.ToLower()}";
        }

        public List<CommandSelector> AppropriateSelectors(AvailableCommand cmd) =>
                commandSelectors.FindAll(sel => sel.IsAppropriateFor(cmd));

        public List<GUIContent> ButtonContentsForCommand(AvailableCommand cmd) {
            return (from sel in AppropriateSelectors(cmd)
                    where sel.ButtonImage != null
                    select new GUIContent(sel.ButtonImage, sel.HeaderString)).ToList();
        }

        private List<CommandSelector> commandSelectors;

        public void Awake() {
            commandSelectors = new List<CommandSelector>();

            foreach (Transform child in gameObject.transform) {
                var sel = child.gameObject.GetComponent<CommandSelector>();
                if (sel != null) { commandSelectors.Add(sel); }
            }

            foreach (var kvp in commandSelectors) {
                kvp.gameObject.SetActive(true);
                kvp.Hide();
            }
        }

        public void Start() {
            foreach (var kvp in commandSelectors) { kvp.gameObject.SetActive(false); }
        }

        public void Update() {
            // '?' key (Shift + /) toggles help panel when a command is selected
            if (Selector != null && Input.GetKeyDown(KeyCode.Slash) &&
                (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))) {
                InfoButtonClicked();
            }
        }

        public void PointerEnteredCommitButton() {
            if (Selector != null) {
                if (!Selector.EnableCommitButton) {
                    if (string.IsNullOrEmpty(Selector.DisabledCommitButtonReason)) {
                        commandWarningPanelController.SetWarning(
                                "Invalid",
                                "CROSBY NEEDS TO PUT SOME TEXT HERE");
                    } else {
                        commandWarningPanelController.SetWarning(
                                "Invalid",
                                Selector.DisabledCommitButtonReason);
                    }
                } else if (Selector.WarnOnCommitButton) {
                    commandWarningPanelController.SetWarning(
                            "Are you sure?",
                            Selector.CommitWarningText);
                }
            }
        }

        public void PointerExitedCommitButton() { commandWarningPanelController.ClearWarning(); }

        /// <summary>
        /// Called when the info button is clicked. Shows help for the current command.
        /// </summary>
        public void InfoButtonClicked() {
            if (Selector == null) return;

            string tutorialId = GetCurrentCommandTutorialId();
            if (tutorialId != null) { TutorialManager.Instance?.ShowCommandHelp(tutorialId); }
        }

        public void OnGUI() {
            var eventType = Event.current.type;
            try {
                if (Selector == null) {
                    commitCommandButton.gameObject.SetActive(false);
                    if (infoButton != null) { infoButton.gameObject.SetActive(false); }
                } else {
                    bool disableWarningPanel = !commitCommandButton.gameObject.activeSelf;

                    if (Selector.WarnOnCommitButton) {
                        commitButtonText.text =
                                $"<color=#FF0000FF>{Selector.CommitButtonString}</color>";
                    } else {
                        commitButtonText.text = Selector.CommitButtonString;
                    }
                    commitCommandButton.gameObject.SetActive(true);
                    commitCommandButton.interactable = Selector.EnableCommitButton;

                    // Show info button when a command is selected
                    if (infoButton != null) { infoButton.gameObject.SetActive(true); }

                    if (disableWarningPanel) {
                        MainQueue.Q.EnqueueForNextUpdate(
                                () => { commandWarningPanelController.ClearWarning(); });
                    }
                }
            } catch (Exception e) {
                Debug.Log($"Event type is {eventType}");
                errorHandler.Add(e);
            }
        }
    }
}
