// Copyright (c) 2025 TerraByte Inc.
//
// This script is the View component for the Better Git tool. Its only
// responsibility is to draw the UI based on the state provided by the
// ArbitratorController.

using System.Linq;
using UnityEngine;
using UnityEditor;

namespace Terra.Arbitrator.GUI
{
    public class ArbitratorWindow : EditorWindow
    {
        private ArbitratorController _controller;
        private string _commitMessage = "";
        private Vector2 _scrollPosition;
        private GUIStyle _evenRowStyle;
        private bool _stylesInitialized;

        [MenuItem("Version Control/Better Git")]
        public static void ShowWindow()
        {
            var window = GetWindow<ArbitratorWindow>();
            window.titleContent = new GUIContent("Better Git", EditorGUIUtility.IconContent("d_UnityEditor.VersionControl").image);
        }
        
        private void OnEnable()
        {
            _controller = new ArbitratorController(
                requestRepaint: Repaint,
                displayDialog: (heading, message) => EditorUtility.DisplayDialog(heading, message, "Yes", "No")
            );
            
            _controller.OnEnable();
        }
        
        private void InitializeStyles()
        {
            if (_stylesInitialized) return;

            _evenRowStyle = new GUIStyle();
            
            var texture = new Texture2D(1, 1);
            var color = EditorGUIUtility.isProSkin 
                ? new Color(0.3f, 0.3f, 0.3f, 0.3f) 
                : new Color(0.8f, 0.8f, 0.8f, 0.5f);
            texture.SetPixel(0, 0, color);
            texture.Apply();
            
            _evenRowStyle.normal.background = texture;
            
            _stylesInitialized = true;
        }

        private void OnGUI()
        {
            InitializeStyles();
            DrawToolbar();
            EditorGUILayout.Space();
            DrawMessageArea();
            DrawMainContent();
        }
        
        private void DrawToolbar()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            EditorGUI.BeginDisabledGroup(_controller.IsLoading);

            if (GUILayout.Button(new GUIContent("Refresh", EditorGUIUtility.IconContent("Refresh").image), EditorStyles.toolbarButton, GUILayout.Width(80)))
            {
                _controller.Refresh();
            }

            if (GUILayout.Button(new GUIContent("Pull", EditorGUIUtility.IconContent("CollabPull").image), EditorStyles.toolbarButton, GUILayout.Width(80)))
            {
                _controller.Pull();
            }
            
            if (_controller.Changes is { Count: > 0 })
            {
                if (GUILayout.Button("Select All", EditorStyles.toolbarButton, GUILayout.Width(80)))
                {
                    _controller.SetAllSelection(true);
                }
                if (GUILayout.Button("Deselect All", EditorStyles.toolbarButton, GUILayout.Width(80)))
                {
                    _controller.SetAllSelection(false);
                }
            
                GUILayout.FlexibleSpace();

                var noChanges = !_controller.Changes.Any();
                EditorGUI.BeginDisabledGroup(noChanges);
                var originalColor = UnityEngine.GUI.backgroundColor;
                UnityEngine.GUI.backgroundColor = new Color(1f, 0.5f, 0.5f, 0.8f);

                if (GUILayout.Button(new GUIContent("Reset All", EditorGUIUtility.IconContent("d_TreeEditor.Trash").image), EditorStyles.toolbarButton, GUILayout.Width(100)))
                {
                    EditorApplication.delayCall += _controller.ResetAll;
                }
            
                UnityEngine.GUI.backgroundColor = originalColor;
                EditorGUI.EndDisabledGroup();
            }

            EditorGUI.EndDisabledGroup();
            
            if (_controller.IsLoading)
            {
                GUILayout.FlexibleSpace();
                GUILayout.Label(_controller.LoadingMessage);
            }

            EditorGUILayout.EndHorizontal();
        }
        
        private void DrawMessageArea()
        {
            if (!string.IsNullOrEmpty(_controller.ErrorMessage))
            {
                EditorGUILayout.HelpBox(_controller.ErrorMessage, MessageType.Error);
            }
            else if (!string.IsNullOrEmpty(_controller.InfoMessage) && !_controller.IsLoading)
            {
                EditorGUILayout.HelpBox(_controller.InfoMessage, MessageType.Info);
            }
        }
        
        private void DrawMainContent()
        {
            if (_controller.IsLoading)
            {
                GUILayout.FlexibleSpace();
                EditorGUILayout.BeginHorizontal();
                GUILayout.FlexibleSpace();
                GUILayout.Label("Loading...", EditorStyles.largeLabel);
                GUILayout.FlexibleSpace();
                EditorGUILayout.EndHorizontal();
                GUILayout.FlexibleSpace();
            }
            else if (_controller.Changes != null && _controller.Changes.Any())
            {
                DrawChangesList();
                DrawCommitSection();
            }
            else
            {
                EditorGUILayout.HelpBox("You are up-to-date! No local changes detected.", MessageType.Info);
            }
        }

        private void DrawChangesList()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
            EditorGUILayout.LabelField("Commit", GUILayout.Width(45));
            EditorGUILayout.LabelField("Status", GUILayout.Width(50));
            EditorGUILayout.LabelField("File Path");
            EditorGUILayout.LabelField("Actions", GUILayout.Width(130));
            EditorGUILayout.EndHorizontal();

            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.ExpandHeight(true));
            for (var i = 0; i < _controller.Changes.Count; i++)
            {
                var change = _controller.Changes[i];
                var rowStyle = i % 2 == 0 ? _evenRowStyle : GUIStyle.none;
                
                EditorGUILayout.BeginHorizontal(rowStyle);

                if (change.Status == LibGit2Sharp.ChangeKind.Conflicted)
                {
                    EditorGUI.BeginDisabledGroup(true);
                    EditorGUILayout.Toggle(false, GUILayout.Width(45));
                    EditorGUI.EndDisabledGroup();
                }
                else
                {
                    change.IsSelectedForCommit = EditorGUILayout.Toggle(change.IsSelectedForCommit, GUILayout.Width(45));
                }

                string status;
                Color statusColor;

                switch (change.Status)
                {
                    case LibGit2Sharp.ChangeKind.Added: status = "[+]"; statusColor = Color.green; break;
                    case LibGit2Sharp.ChangeKind.Deleted: status = "[-]"; statusColor = Color.red; break;
                    case LibGit2Sharp.ChangeKind.Modified: status = "[M]"; statusColor = new Color(1.0f, 0.6f, 0.0f); break;
                    case LibGit2Sharp.ChangeKind.Renamed: status = "[R]"; statusColor = new Color(0.6f, 0.6f, 1.0f); break;
                    case LibGit2Sharp.ChangeKind.Conflicted: status = "[C]"; statusColor = Color.magenta; break;
                    default: status = "[?]"; statusColor = Color.white; break;
                }
                
                var filePathDisplay = change.Status == LibGit2Sharp.ChangeKind.Renamed
                    ? $"{change.OldFilePath} -> {change.FilePath}"
                    : change.FilePath;

                var originalColor = UnityEngine.GUI.color;
                UnityEngine.GUI.color = statusColor;
                EditorGUILayout.LabelField(new GUIContent(status, change.Status.ToString()), GUILayout.Width(50));
                UnityEngine.GUI.color = originalColor;

                EditorGUILayout.LabelField(new GUIContent(filePathDisplay, filePathDisplay));

                EditorGUILayout.BeginHorizontal(GUILayout.Width(120));
                EditorGUI.BeginDisabledGroup(_controller.IsLoading);

                if (change.Status == LibGit2Sharp.ChangeKind.Conflicted)
                {
                    if (GUILayout.Button("Resolve", GUILayout.Width(70)))
                    {
                        EditorApplication.delayCall += () => _controller.ResolveConflict(change);
                    }
                }
                else
                {
                    if (GUILayout.Button("Diff", GUILayout.Width(45)))
                    {
                        EditorApplication.delayCall += () => _controller.DiffFile(change);
                    }
                }
                
                if (GUILayout.Button(new GUIContent("Reset", "Revert changes for this file"), GUILayout.Width(55)))
                {
                    EditorApplication.delayCall += () => _controller.ResetFile(change);
                }
                
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();
                
                EditorGUILayout.EndHorizontal();
            }
            EditorGUILayout.EndScrollView();
        }
        
        private void DrawCommitSection()
        {
            EditorGUILayout.Space(10);
            if (_controller.Changes.Any(c => c.Status == LibGit2Sharp.ChangeKind.Conflicted))
            {
                EditorGUILayout.HelpBox("You must resolve all conflicts before you can commit.", MessageType.Warning);
                return;
            }
            
            EditorGUILayout.LabelField("Commit & Push", EditorStyles.boldLabel);
            _commitMessage = EditorGUILayout.TextArea(_commitMessage, GUILayout.Height(60), GUILayout.ExpandWidth(true));

            var isPushDisabled = string.IsNullOrWhiteSpace(_commitMessage) || !_controller.Changes.Any(c => c.IsSelectedForCommit);

            EditorGUI.BeginDisabledGroup(isPushDisabled);
            if (GUILayout.Button("Commit & Push Selected Files", GUILayout.Height(40)))
            {
                _controller.CommitAndPush(_commitMessage);
                _commitMessage = "";
            }
            EditorGUI.EndDisabledGroup();
            
            if (isPushDisabled)
            {
                EditorGUILayout.HelpBox("Please enter a commit message and select at least one file.", MessageType.Warning);
            }
        }
    }
}
