using System;
using Codice.Utils;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.UIElements;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace Unity.PlasticSCM.Editor.Views.BranchExplorer
{
    internal class BrExSearchField : VisualElement
    {
        internal string Text
        {
            get { return mSearchField.value; }
            set { mSearchField.value = value; }
        }

        internal event Action DelayedSearchTextChanged;
        internal event Action NextSearchResultRequested;
        internal event Action PreviousSearchResultRequested;

        internal BrExSearchField()
        {
            CreateGUI();

            mSearchRunner = new DelayedActionBySecondsRunner(
                OnDelayedSearchChanged,
                UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL);
        }

        internal void Dispose()
        {
            mSearchField.UnregisterValueChangedCallback(OnSearchFieldChanged);
            mSearchField.UnregisterCallback<KeyDownEvent>(OnSearchFieldKeyDown, TrickleDown.TrickleDown);

            mPreviousButton.UnregisterCallback<MouseEnterEvent>(OnNavigationButtonMouseEnter);
            mPreviousButton.UnregisterCallback<MouseLeaveEvent>(OnNavigationButtonMouseLeave);

            mNextButton.UnregisterCallback<MouseEnterEvent>(OnNavigationButtonMouseEnter);
            mNextButton.UnregisterCallback<MouseLeaveEvent>(OnNavigationButtonMouseLeave);
        }

        internal void FocusSearchField()
        {
            mSearchField.Focus();
        }

        internal void UpdateSearchCounter(int currentIndex, int totalResults)
        {
            if (string.IsNullOrEmpty(mSearchField.value))
                return;

            if (totalResults == 0)
            {
                mSearchCounterLabel.text = "0/0";
                mPreviousButton.SetEnabled(false);
                mNextButton.SetEnabled(false);
            }
            else
            {
                mSearchCounterLabel.text = string.Format("{0}/{1}", currentIndex, totalResults);
                mPreviousButton.SetEnabled(true);
                mNextButton.SetEnabled(true);
            }
        }

        void OnDelayedSearchChanged()
        {
            DelayedSearchTextChanged?.Invoke();
        }

        void CreateGUI()
        {
            style.flexDirection = FlexDirection.Row;
            style.alignItems = Align.Center;

            mSearchField = BuildSearchField();
            Add(mSearchField);

            var overlayContainer = BuildOverlayContainer();
            Add(overlayContainer);
        }

        ToolbarSearchField BuildSearchField()
        {
            var searchField = new ToolbarSearchField();
            searchField.style.width = 220;
            searchField.style.flexGrow = 1;
            searchField.tooltip = string.Format("{0}{1}{2}",
                PlasticLocalization.Name.BranchExplorerSearchFieldTooltip.GetString(),
                Environment.NewLine,
                GetSearchTextBoxShortcutsTooltipString());
            searchField.RegisterValueChangedCallback(OnSearchFieldChanged);
            searchField.RegisterCallback<KeyDownEvent>(OnSearchFieldKeyDown, TrickleDown.TrickleDown);

            var textField = searchField.Q<TextField>();
            if (textField != null)
            {
                textField.style.paddingRight = 55;
                textField.SetTextCursor();
            }

            return searchField;
        }

        VisualElement BuildOverlayContainer()
        {
            var container = new VisualElement();
            container.style.position = Position.Absolute;
            container.style.right = 18;
            container.style.top = 0;
            container.style.bottom = 0;
            container.style.flexDirection = FlexDirection.Row;
            container.style.alignItems = Align.Center;
            container.pickingMode = PickingMode.Ignore;

            mSearchCounterLabel = BuildSearchCounterLabel();
            container.Add(mSearchCounterLabel);

            mPreviousButton = CreateNavigationButton(
                OnPreviousButtonClicked,
                PlasticLocalization.Name.PreviousLabel.GetString(),
                Images.GetArrowCaretLeftIcon(),
                marginRight: 2);
            container.Add(mPreviousButton);

            mNextButton = CreateNavigationButton(
                OnNextButtonClicked,
                PlasticLocalization.Name.NextLabel.GetString(),
                Images.GetArrowCaretRightIcon());
            container.Add(mNextButton);

            return container;
        }

        Label BuildSearchCounterLabel()
        {
            var label = new Label();
            label.style.color = UnityStyles.Colors.SecondaryLabel;
            label.style.fontSize = 11;
            label.style.unityTextAlign = TextAnchor.MiddleCenter;
            label.style.marginLeft = 4;
            label.style.marginRight = 0;
            label.pickingMode = PickingMode.Ignore;
            return label;
        }

        void OnNavigationButtonMouseEnter(MouseEnterEvent evt)
        {
            VisualElement button = (VisualElement)evt.currentTarget;
            button.style.backgroundColor = StyleKeyword.Null;
        }

        void OnNavigationButtonMouseLeave(MouseLeaveEvent evt)
        {
            VisualElement button = (VisualElement)evt.currentTarget;
            button.style.backgroundColor = Color.clear;
        }

        Button CreateNavigationButton(
            Action clickEvent,
            string tooltip,
            Texture2D image,
            float marginRight = 0)
        {
            Button result = new Button(clickEvent);

            result.tooltip = tooltip;
            result.style.backgroundImage = image;
            result.style.width = NAVIGATION_BUTTON_SIZE;
            result.style.height = NAVIGATION_BUTTON_SIZE;
            result.style.marginLeft = 0;
            result.style.marginRight = marginRight;
            result.style.paddingLeft = 0;
            result.style.paddingRight = 0;
            result.style.paddingTop = 0;
            result.style.paddingBottom = 0;
            result.style.borderLeftWidth = 0;
            result.style.borderRightWidth = 0;
            result.style.borderTopWidth = 0;
            result.style.borderBottomWidth = 0;
            result.visible = false;
            result.style.backgroundColor = Color.clear;

            result.SetMouseCursor(MouseCursor.Arrow);
            result.RegisterCallback<MouseEnterEvent>(OnNavigationButtonMouseEnter);
            result.RegisterCallback<MouseLeaveEvent>(OnNavigationButtonMouseLeave);

            return result;
        }

        void OnSearchFieldKeyDown(KeyDownEvent evt)
        {
            KeyboardActions.SearchAction searchAction =
                KeyboardActions.GetSearchAction(evt);

            if (searchAction == KeyboardActions.SearchAction.None)
                return;

            if (searchAction == KeyboardActions.SearchAction.Clean)
            {
                evt.StopPropagation();
                mSearchField.value = string.Empty;
                return;
            }

            if (searchAction == KeyboardActions.SearchAction.PreviousSearch)
            {
                evt.StopPropagation();
                PreviousSearchResultRequested?.Invoke();
                return;
            }

            if (searchAction == KeyboardActions.SearchAction.NextSearch)
            {
                evt.StopPropagation();
                NextSearchResultRequested?.Invoke();
                return;
            }
        }

        void OnSearchFieldChanged(ChangeEvent<string> evt)
        {
            mSearchRunner.Run();
            UpdateSearchControlsVisibility();
        }

        void UpdateSearchControlsVisibility()
        {
            if (string.IsNullOrEmpty(mSearchField.value))
            {
                mSearchCounterLabel.text = string.Empty;
                mSearchCounterLabel.visible = false;
                mPreviousButton.visible = false;
                mNextButton.visible = false;
                return;
            }

            mSearchCounterLabel.visible = true;
            mPreviousButton.visible = true;
            mNextButton.visible = true;
        }

        void OnNextButtonClicked()
        {
            NextSearchResultRequested?.Invoke();
        }

        void OnPreviousButtonClicked()
        {
            PreviousSearchResultRequested?.Invoke();
        }

        static string GetSearchTextBoxShortcutsTooltipString()
        {
            if (PlatformIdentifier.IsWindows())
                return PlasticLocalization.Name
                    .BranchExplorerSearchFieldShortcutsTooltipForWindows.GetString();

            if (PlatformIdentifier.IsMac())
                return PlasticLocalization.Name
                    .BranchExplorerSearchFieldShortcutsTooltipForMacOS.GetString();

            return PlasticLocalization.Name
                .BranchExplorerSearchFieldShortcutsTooltipForLinux.GetString();
        }

        ToolbarSearchField mSearchField;
        Label mSearchCounterLabel;
        Button mPreviousButton;
        Button mNextButton;

        readonly DelayedActionBySecondsRunner mSearchRunner;

        const float NAVIGATION_BUTTON_SIZE = 12f;
    }
}