// Asset Naming Manager — the Project Settings page the documentation keeps pointing at.
using UnityEditor;
using UnityEngine;

namespace AssetNamingManager
{
    /// <summary>
    /// The <c>Edit ▸ Project Settings ▸ Asset Naming Manager</c> page. It is split into two blocks on
    /// purpose: what the rule set asset holds, which travels with the project, and what
    /// <see cref="EditorPrefs"/> holds, which never leaves this machine. Confusing those two is
    /// the usual reason a teammate's scan disagrees with yours, so every field says which it is.
    /// IMGUI rather than UI Toolkit: the settings window is IMGUI, and a UI Toolkit page here
    /// would only add a second style sheet to keep in step with the main window.
    /// </summary>
    public static class NamingManagerSettingsProvider
    {
        /// <summary>Terms that should surface this page in the Project Settings search box.</summary>
        static readonly string[] Keywords =
        {
            "asset", "naming", "cop", "name", "rename", "convention", "rule", "rule set",
            "prefix", "suffix", "case", "pascal", "camel", "snake", "lint", "audit",
            "overlay", "project window", "import", "postprocessor", "scan", "console", "ci"
        };

        static readonly GUIContent RuleSetLabel = new GUIContent(
            "Active rule set",
            "The asset every scan, the import check and CI read their convention from.");

        static readonly GUIContent CheckOnImportLabel = new GUIContent(
            "Check assets on import",
            "Check assets the moment they are imported and warn in the console straight away. " +
            "Saved in the rule set, so it is on for everyone who has the asset.");

        static readonly GUIContent OverlayLabel = new GUIContent(
            "Project window overlay",
            "Draw a severity-coloured dot on offending assets in the Project browser.");

        static readonly GUIContent ScanOnOpenLabel = new GUIContent(
            "Scan when the window opens",
            "Run a scan automatically the first time the window is opened in a session.");

        static readonly GUIContent LogToConsoleLabel = new GUIContent(
            "Log findings to the console",
            "Also print every finding to the Console after a scan.");

        static readonly GUIContent ConfirmFixLabel = new GUIContent(
            "Confirm before fixing",
            "Ask before applying a batch of fixes. Strongly recommended — one batch can rename " +
            "a great many files at once.");

        /// <summary>Registers the page at <see cref="NamingManagerAbout.SettingsPath"/>.</summary>
        [SettingsProvider]
        public static SettingsProvider Create()
        {
            return new SettingsProvider(NamingManagerAbout.SettingsPath, SettingsScope.Project, Keywords)
            {
                label = NamingManagerAbout.ProductName,
                guiHandler = OnGUI
            };
        }

        static void OnGUI(string searchContext)
        {
            // The settings window draws flush against its own edges, and the labels here are long.
            float previousLabelWidth = EditorGUIUtility.labelWidth;
            EditorGUIUtility.labelWidth = 240f;

            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(10f);
            EditorGUILayout.BeginVertical();
            EditorGUILayout.Space();

            DrawRuleSetSection();
            GUILayout.Space(14f);
            DrawPreferencesSection();

            EditorGUILayout.EndVertical();
            GUILayout.Space(10f);
            EditorGUILayout.EndHorizontal();

            EditorGUIUtility.labelWidth = previousLabelWidth;
        }

        // ---------------------------------------------------------------- shared settings

        static void DrawRuleSetSection()
        {
            EditorGUILayout.LabelField("Rule set — shared with your team", EditorStyles.boldLabel);
            EditorGUILayout.LabelField(
                "Everything in this block lives inside the rule set asset. Commit it and the whole " +
                "team scans by one convention. Which rule set is active is remembered per machine.",
                EditorStyles.wordWrappedMiniLabel);
            EditorGUILayout.Space();

            NamingRuleSet ruleSet = NamingManagerSettings.ActiveRuleSet;

            EditorGUI.BeginChangeCheck();
            var picked = (NamingRuleSet)EditorGUILayout.ObjectField(
                RuleSetLabel, ruleSet, typeof(NamingRuleSet), false);
            if (EditorGUI.EndChangeCheck() && picked != ruleSet)
            {
                NamingManagerSettings.ActiveRuleSet = picked;
                ruleSet = picked;
            }

            if (ruleSet == null)
            {
                DrawNoRuleSetHelp();
                return;
            }

            string assetPath = AssetDatabase.GetAssetPath(ruleSet);
            if (!string.IsNullOrEmpty(assetPath))
                EditorGUILayout.LabelField(" ", assetPath, EditorStyles.miniLabel);

            EditorGUI.BeginChangeCheck();
            bool checkOnImport = EditorGUILayout.Toggle(CheckOnImportLabel, ruleSet.checkOnImport);
            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(ruleSet, "Toggle check on import");
                ruleSet.checkOnImport = checkOnImport;
                EditorUtility.SetDirty(ruleSet);
            }

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Edit rules…", GUILayout.Width(120f)))
                UI.NamingManagerWindow.Open();
            if (GUILayout.Button("Show in project", GUILayout.Width(140f)))
                EditorGUIUtility.PingObject(ruleSet);
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
        }

        static void DrawNoRuleSetHelp()
        {
            EditorGUILayout.Space();
            EditorGUILayout.HelpBox(
                "This project has no rule set yet, so there is nothing to scan against. A rule set is " +
                "an asset holding your naming convention — create one here, commit it, and the rest " +
                "of the tool comes to life.",
                MessageType.Info);

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Create a rule set", GUILayout.Width(160f)))
            {
                // The window's Rules tab can swap the preset afterwards; this is only a starting point.
                NamingManagerSettings.CreateRuleSet(NamingPreset.UnityStandard);
            }
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
        }

        // ---------------------------------------------------------------- per-user preferences

        static void DrawPreferencesSection()
        {
            EditorGUILayout.LabelField("Preferences — this machine only", EditorStyles.boldLabel);
            EditorGUILayout.LabelField(
                "Kept in EditorPrefs and namespaced per checkout. Nothing here is committed and " +
                "changing it affects nobody else on the team.",
                EditorStyles.wordWrappedMiniLabel);
            EditorGUILayout.Space();

            EditorGUI.BeginChangeCheck();
            bool overlay = EditorGUILayout.Toggle(OverlayLabel, NamingManagerSettings.ShowProjectOverlay);
            if (EditorGUI.EndChangeCheck())
            {
                NamingManagerSettings.ShowProjectOverlay = overlay;
                // Dots already on screen are the Project window's own drawing; it needs telling.
                EditorApplication.RepaintProjectWindow();
            }

            EditorGUI.BeginChangeCheck();
            bool scanOnOpen = EditorGUILayout.Toggle(ScanOnOpenLabel, NamingManagerSettings.ScanOnOpen);
            if (EditorGUI.EndChangeCheck())
                NamingManagerSettings.ScanOnOpen = scanOnOpen;

            EditorGUI.BeginChangeCheck();
            bool logToConsole = EditorGUILayout.Toggle(LogToConsoleLabel, NamingManagerSettings.LogToConsole);
            if (EditorGUI.EndChangeCheck())
                NamingManagerSettings.LogToConsole = logToConsole;

            EditorGUI.BeginChangeCheck();
            bool confirmBeforeFixing = EditorGUILayout.Toggle(ConfirmFixLabel, NamingManagerSettings.ConfirmBeforeFixing);
            if (EditorGUI.EndChangeCheck())
                NamingManagerSettings.ConfirmBeforeFixing = confirmBeforeFixing;

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Reset my preferences", GUILayout.Width(180f)))
                ResetPreferences();
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
        }

        static void ResetPreferences()
        {
            bool confirmed = EditorUtility.DisplayDialog(
                "Reset preferences",
                "Put the toggles on this machine back to their defaults?\n\n" +
                "Your rule sets are not touched, and nobody else on the team sees a change.",
                "Reset",
                "Cancel");

            if (!confirmed) return;

            NamingManagerSettings.ResetPreferences();
            EditorApplication.RepaintProjectWindow();
        }
    }
}
