using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace Gyvr.Mythril2D
{
    [Serializable]
    public class SceneMetadataEntry
    {
        public string scenePath;
        public bool isFavorite;
        public string category = "";
        public string subcategory = "";
        public List<string> tags = new();
        public string SceneName => Path.GetFileNameWithoutExtension(scenePath);
    }

    public static class SceneMetadataManager
    {
        const string kAssetPath = "Assets/Mythril2D/Core/Editor/SceneMetadata.asset";
        static SceneMetadataAsset s_Asset;

        public static SceneMetadataAsset Asset => s_Asset ?? (s_Asset = LoadOrCreate());

        static SceneMetadataAsset LoadOrCreate()
        {
            var asset = AssetDatabase.LoadAssetAtPath<SceneMetadataAsset>(kAssetPath);
            if (asset != null) return asset;

            asset = ScriptableObject.CreateInstance<SceneMetadataAsset>();
            var dir = Path.GetDirectoryName(kAssetPath);
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
            AssetDatabase.CreateAsset(asset, kAssetPath);
            AssetDatabase.SaveAssets();
            return asset;
        }

        static void Save()
        {
            EditorUtility.SetDirty(s_Asset);
            AssetDatabase.SaveAssets();
        }

        static SceneMetadataEntry GetOrCreate(string path)
        {
            var e = Asset.entries.FirstOrDefault(x => x.scenePath == path);
            if (e == null)
            {
                e = new SceneMetadataEntry { scenePath = path };
                Asset.entries.Add(e);
            }
            return e;
        }

        public static SceneMetadataEntry GetEntry(string path) => Asset.entries.FirstOrDefault(x => x.scenePath == path);

        public static void SetFavorite(string path, bool fav) { GetOrCreate(path).isFavorite = fav; Save(); }
        public static bool IsFavorite(string path) => GetEntry(path)?.isFavorite ?? false;
        public static IEnumerable<string> GetFavorites() => Asset.entries.Where(e => e.isFavorite).Select(e => e.scenePath);

        public static void SetCategory(string path, string cat) { GetOrCreate(path).category = cat; Save(); }
        public static string GetCategory(string path) => GetEntry(path)?.category ?? "";

        public static void SetSubcategory(string path, string sub) { GetOrCreate(path).subcategory = sub; Save(); }
        public static string GetSubcategory(string path) => GetEntry(path)?.subcategory ?? "";

        public static void AddTag(string path, string tag)
        {
            var e = GetOrCreate(path);
            if (!e.tags.Contains(tag)) { e.tags.Add(tag); Save(); }
        }

        public static void RemoveTag(string path, string tag)
        {
            var e = GetOrCreate(path);
            if (e.tags.Remove(tag)) Save();
        }

        public static void ToggleTag(string path, string tag)
        {
            var e = GetOrCreate(path);
            if (e.tags.Contains(tag)) e.tags.Remove(tag);
            else e.tags.Add(tag);
            Save();
        }

        public static List<string> GetTags(string path) => GetEntry(path)?.tags ?? new List<string>();
        public static bool HasTag(string path, string tag) => GetEntry(path)?.tags.Contains(tag) ?? false;

        public static void AddCategory(string cat)
        {
            if (!string.IsNullOrWhiteSpace(cat) && !Asset.availableCategories.Contains(cat))
            { Asset.availableCategories.Add(cat); Save(); }
        }

        public static void RemoveCategory(string cat)
        {
            if (!Asset.availableCategories.Remove(cat)) return;
            foreach (var e in Asset.entries.Where(x => x.category == cat)) e.category = "";
            Save();
        }

        public static void AddSubcategory(string sub)
        {
            if (!string.IsNullOrWhiteSpace(sub) && !Asset.availableSubcategories.Contains(sub))
            { Asset.availableSubcategories.Add(sub); Save(); }
        }

        public static void RemoveSubcategory(string sub)
        {
            if (!Asset.availableSubcategories.Remove(sub)) return;
            foreach (var e in Asset.entries.Where(x => x.subcategory == sub)) e.subcategory = "";
            Save();
        }

        public static void AddAvailableTag(string tag)
        {
            if (!string.IsNullOrWhiteSpace(tag) && !Asset.availableTags.Contains(tag))
            { Asset.availableTags.Add(tag); Save(); }
        }

        public static void RemoveAvailableTag(string tag)
        {
            if (!Asset.availableTags.Remove(tag)) return;
            foreach (var e in Asset.entries) e.tags.Remove(tag);
            Save();
        }

        public static int CleanupOrphans()
        {
            var existing = new HashSet<string>(SceneUtil.GetAllScenesInAssetDatabase());
            int n = Asset.entries.RemoveAll(e => !existing.Contains(e.scenePath));
            if (n > 0) Save();
            return n;
        }
    }
}
