﻿using System.Collections.Generic;
using System.IO;
using JLGames.RocketDriver.Actions.Utils;
using JLGames.RocketDriver.CSharp.Utils;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;

namespace JLGames.RocketDriver.Editor.Infra
{
    public class EditorAssetIndex : ScriptableObject
    {
        [SerializeField] private bool m_IncludeFolder = false;
        [SerializeField] private List<string> m_IncludeExtensions = new List<string>();
        [SerializeField] private List<string> m_SourceFolders = new List<string>();
        [SerializeField] private List<EditorAssetIndexInfo> m_References = new List<EditorAssetIndexInfo>();
        private readonly List<AssetDetail> m_AssetDetails = new List<AssetDetail>();

        public bool IncludeFolder => m_IncludeFolder;
        public List<string> IncludeExtensions => m_IncludeExtensions;
        public List<string> SourceFolders => m_SourceFolders;
        public List<EditorAssetIndexInfo> References => m_References;

        public bool ContainsExtension => null != m_IncludeExtensions && m_IncludeExtensions.Count > 0;
        public bool ContainsSource => null != m_SourceFolders && m_SourceFolders.Count > 0;
        public bool ContainsReference => null != m_References && m_References.Count > 0;

        public void SetIncludeFolder(bool includeFolder)
        {
            m_IncludeFolder = includeFolder;
        }

        public void SetIncludeExtensions(string[] includeExtensions)
        {
            m_IncludeExtensions.Clear();
            if (null == includeExtensions || includeExtensions.Length == 0) return;
            m_IncludeExtensions.AddRange(includeExtensions);
        }

        public void SetSourceFolders(string[] sourceFolders)
        {
            m_SourceFolders.Clear();
            if (null == sourceFolders || sourceFolders.Length == 0) return;
            m_SourceFolders.AddRange(sourceFolders);
        }

        public EditorAssetIndexInfo FindByName(string assetName)
        {
            return m_References.Find(info => info.AssetName == assetName);
        }

        public EditorAssetIndexInfo FindByGuid(string guid, long locaFilelId = 0)
        {
            return m_References.Find(info => info.Guid == guid && info.FileId == locaFilelId);
        }

        public EditorAssetIndexInfo[] FindByPath(string assetPath)
        {
            return m_References.FindAll(info => info.UnityPath == assetPath).ToArray();
        }

        public void UpdateAssetIndex()
        {
            CheckAndUpdateExtensions();
            if (!ContainsSource) return;
            UpdateAssetDetails();
            if (m_AssetDetails.Count == 0) return;
            UpdateIndex();
        }

        //--------------------------------------------

        private readonly HashSet<string> m_TempSet = new HashSet<string>();

        private void UpdateIndex()
        {
            m_References.Clear();
            string quid;
            long localId;
            m_AssetDetails.ForEach(detail =>
            {
                var importer = AssetImporter.GetAtPath(detail.UnityPath);
                if (importer is TextureImporter)
                {
                    var texImporter = (TextureImporter) importer;
                    if (texImporter.textureType == TextureImporterType.Sprite)
                    {
                        AppendSpriteIndexs(detail.UnityPath, detail.SystemInfo.Name);
                    }
                }

                var asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(detail.UnityPath);
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset.GetInstanceID(), out quid, out localId);
                m_References.Add(new EditorAssetIndexInfo
                {
                    AssetName = detail.SystemInfo.Name,
                    UnityPath = detail.UnityPath,
                    Guid = quid,
                    FileId = localId,
                    SpriteId = ""
                });
            });
            m_References.Sort();
        }

        private void AppendSpriteIndexs(string atlasPath, string fileName)
        {
            var sprites = AssetDatabase.LoadAllAssetsAtPath(atlasPath);
            for (var index = 1; index < sprites.Length; index++) //0为图集
            {
                var instance = sprites[index];
                long localId;
                string quid;
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(instance.GetInstanceID(), out quid, out localId);
                m_References.Add(new EditorAssetIndexInfo
                {
                    AssetName = 0 == index ? fileName : instance.name,
                    UnityPath = atlasPath,
                    Guid = quid,
                    FileId = localId,
                    SpriteId = 0 == index ? "" : ((Sprite) instance).GetSpriteID().ToString()
                });
            }
        }

        private void UpdateAssetDetails()
        {
            m_AssetDetails.Clear();
            var paths = AssetDatabase.GetAllAssetPaths();
            foreach (var path in paths)
            {
                if (!CheckInSource(path)) continue;
                var absPath = UnityPathUtil.CombineUnityPath(Application.dataPath + "/../", path);
                var isFolder = DirectoryUtil.Exists(absPath);
                var isFile = RocketDriver.CSharp.Utils.FileUtil.Exists(absPath);
                if (!m_IncludeFolder && isFolder) continue;
                if (isFile)
                {
                    var fileInfo = new FileInfo(absPath);
                    if (!ContainsExtension)
                    {
                        m_AssetDetails.Add(new AssetDetail {UnityPath = path, SystemInfo = fileInfo, IsFile = true});
                        continue;
                    }

                    var ext = fileInfo.Extension.ToLower().Substring(1);
                    if (m_IncludeExtensions.Contains(ext))
                    {
                        m_AssetDetails.Add(new AssetDetail {UnityPath = path, SystemInfo = fileInfo, IsFile = true});
                    }

                    continue;
                }

                if (isFolder)
                {
                    var folderInfo = new DirectoryInfo(absPath);
                    m_AssetDetails.Add(new AssetDetail {UnityPath = path, SystemInfo = folderInfo, IsFile = false});
                }
            }
        }

        private bool CheckInSource(string path)
        {
            if (!ContainsSource) return false;
            foreach (var sourceFolder in m_SourceFolders)
            {
                if (path == sourceFolder || path.StartsWith(sourceFolder + "/")) return true;
            }

            return false;
        }

        private void CheckAndUpdateExtensions()
        {
            if (!ContainsExtension) return;

            m_TempSet.Clear();
            for (var index = m_IncludeExtensions.Count - 1; index >= 0; index--)
            {
                var newExt = m_IncludeExtensions[index].Trim().ToLower();
                if (string.IsNullOrEmpty(newExt) || m_TempSet.Contains(newExt))
                {
                    m_IncludeExtensions.RemoveAt(index);
                    continue;
                }

                m_IncludeExtensions[index] = newExt;
                m_TempSet.Add(newExt);
            }
        }
    }
}