using System;
using System.Collections.Generic;

using UnityEditor;
using UnityEngine;


namespace AIRuntime.Editor
{
    internal sealed class AIRuntimeKanbanAgentCard
    {
        public string Id;

        public string Label;

        public bool IsActive;

        public bool IsRunning;

        public string ActiveTaskTitle;

        public int AssignedTaskCount;

        public int PendingTaskCount;

        public string ConfigurationPath;
    }


    /// <summary>
    /// Dockable live view of the agents available to the AIRuntime Kanban
    /// board. Saved agent configurations are discovered by the board and
    /// appear here automatically.
    /// </summary>
    public sealed class AIRuntimeKanbanAgentsWindow :
        EditorWindow
    {
        [NonSerialized]
        private AIRuntimeKanbanSession _owner;

        private Vector2 _scroll;

        private double _nextAgentRefreshAt;


        [MenuItem("Window/AIRuntime/Kanban Agents")]
        public static void OpenFromMenu()
        {
            AIRuntimeKanbanSession[] boards =
                Resources.FindObjectsOfTypeAll<AIRuntimeKanbanSession>();

            Open(
                boards.Length >
                0
                    ? boards[0]
                    : null);
        }


        internal static void Open(
            AIRuntimeKanbanSession owner)
        {
            AIRuntimeKanbanAgentsWindow window =
                GetWindow<AIRuntimeKanbanAgentsWindow>();

            window._owner =
                owner;

            window.titleContent =
                new GUIContent(
                    "Kanban Agents");

            window.minSize =
                new Vector2(
                    280,
                    220);

            window.Show();
            window.Focus();
            window.RefreshAgents();
        }


        private void OnEnable()
        {
            titleContent =
                new GUIContent(
                    "Kanban Agents");

            minSize =
                new Vector2(
                    280,
                    220);

            RecoverOwner();
            RefreshAgents();
        }


        private void OnGUI()
        {
            DrawToolbar();

            if (_owner ==
                null)
            {
                EditorGUILayout.HelpBox(
                    "Open the AIRuntime Kanban board to view its agents.",
                    MessageType.Info);

                if (GUILayout.Button(
                        "Open Kanban"))
                {
                    AIRuntimeKanbanSession.Open();
                    RecoverOwner();
                }

                return;
            }

            IReadOnlyList<AIRuntimeKanbanAgentCard> agents =
                _owner.GetKanbanAgentCards();

            if (agents.Count ==
                0)
            {
                EditorGUILayout.HelpBox(
                    "No saved or built-in Kanban agents were found.",
                    MessageType.Info);

                return;
            }

            _scroll =
                EditorGUILayout.BeginScrollView(
                    _scroll);

            foreach (
                AIRuntimeKanbanAgentCard agent
                in agents)
            {
                DrawAgentCard(
                    agent);
            }

            EditorGUILayout.EndScrollView();
        }


        private void DrawToolbar()
        {
            using (
                new EditorGUILayout.HorizontalScope(
                    EditorStyles.toolbar))
            {
                GUILayout.Label(
                    "Agents",
                    EditorStyles.boldLabel);

                GUILayout.FlexibleSpace();

                if (GUILayout.Button(
                        "Refresh",
                        EditorStyles.toolbarButton))
                {
                    RefreshAgents();
                }
            }
        }


        private void DrawAgentCard(
            AIRuntimeKanbanAgentCard agent)
        {
            Color previousColor =
                GUI.backgroundColor;

            GUI.backgroundColor =
                GetAgentCardColor(
                    agent.IsActive);

            Rect cardRect =
                EditorGUILayout.BeginVertical(
                    EditorStyles.helpBox);

            GUI.backgroundColor =
                previousColor;

            using (
                new EditorGUILayout.HorizontalScope())
            {
                GUILayout.Label(
                    agent.Label,
                    EditorStyles.boldLabel);

                GUILayout.FlexibleSpace();

                GUILayout.Label(
                    agent.IsRunning
                        ? "RUNNING"
                        : agent.IsActive
                            ? "ACTIVE"
                            : "INACTIVE",
                    EditorStyles.miniBoldLabel,
                    GUILayout.Width(
                        58));

                GUIStyle actionButtonStyle =
                    new GUIStyle(
                        GUI.skin.button)
                    {
                        wordWrap =
                            false
                    };

                if (GUILayout.Button(
                        agent.IsActive
                            ? "Deactivate"
                            : "Activate",
                        actionButtonStyle,
                        GUILayout.Width(
                            92)))
                {
                    _owner.SetKanbanAgentActive(
                        agent.Id,
                        !agent.IsActive);
                }
            }

            GUILayout.Label(
                $"ID: {agent.Id}",
                EditorStyles.miniLabel);

            if (agent.IsRunning &&
                !string.IsNullOrWhiteSpace(
                    agent.ActiveTaskTitle))
            {
                GUILayout.Label(
                    $"Task: {agent.ActiveTaskTitle}",
                    EditorStyles.wordWrappedMiniLabel);
            }

            GUILayout.Label(
                $"Assigned: {agent.AssignedTaskCount}    Pending: {agent.PendingTaskCount}",
                EditorStyles.miniLabel);

            EditorGUILayout.EndVertical();

            Event current =
                Event.current;

            if (current.type ==
                    EventType.MouseUp &&
                current.button ==
                    0 &&
                cardRect.Contains(
                    current.mousePosition))
            {
                OpenAgentSettings(
                    agent);

                current.Use();
            }
        }


        private static void OpenAgentSettings(
            AIRuntimeKanbanAgentCard agent)
        {
            if (string.IsNullOrWhiteSpace(
                    agent.ConfigurationPath))
            {
                EditorUtility.DisplayDialog(
                    "Agent settings",
                    $"No saved configuration file was found for '{agent.Label}'. Save this agent from the Chat Console first.",
                    "OK");

                AIRuntimeChatConsole.Open();
                return;
            }

            AIRuntimeChatConsole.OpenAgentConfiguration(
                agent.ConfigurationPath);
        }


        private void OnInspectorUpdate()
        {
            if (EditorApplication.timeSinceStartup >=
                _nextAgentRefreshAt)
            {
                _nextAgentRefreshAt =
                    EditorApplication.timeSinceStartup +
                    1d;

                RefreshAgents();
            }

            Repaint();
        }


        private void RefreshAgents()
        {
            if (_owner ==
                null)
            {
                RecoverOwner();
            }

            _owner?.RefreshKanbanAgents();
            Repaint();
        }


        private void RecoverOwner()
        {
            AIRuntimeKanbanSession[] boards =
                Resources.FindObjectsOfTypeAll<AIRuntimeKanbanSession>();

            _owner =
                boards.Length >
                0
                    ? boards[0]
                    : null;
        }


        private static Color GetAgentCardColor(
            bool isActive)
        {
            return isActive
                ? new Color(
                    0.55f,
                    0.9f,
                    0.6f)
                : Color.white;
        }
    }
}
