﻿using System.IO;
using JLGames.RocketDriver.Actions.Utils;
using JLGames.RocketDriver.CSharp.Utils;
using UnityEditor;
using UnityEngine;
using FileUtil = JLGames.RocketDriver.CSharp.Utils.FileUtil;

namespace JLGames.RocketDriver.Editor.Infra
{
    public static class EditorScriptableUtil
    {
        /// <summary>
        /// Generate ScriptableObject assets to the currently selected directory, and optionally set a name
        /// 生成ScriptableObject资产到当前选中的目录, 可指定名称
        /// </summary>
        /// <param name="assetName"></param>
        /// <param name="override"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GenScriptableAssetToSelection<T>(string assetName = null, bool @override = false)
            where T : ScriptableObject
        {
            var asset = ScriptableObject.CreateInstance<T>();
            if (null == asset)
            {
                Debug.LogWarning($"{typeof(T)} Undefined. ");
                return null;
            }

            GenScriptableAssetToSelection(asset, assetName, @override);
            return asset;
        }

        /// <summary>
        /// Generate ScriptableObject assets to the currently selected directory, and optionally set a name
        /// 生成ScriptableObject资产到当前选中的目录, 可指定名称
        /// </summary>
        /// <param name="asset"></param>
        /// <param name="assetName"></param>
        /// <param name="override"></param>
        public static void GenScriptableAssetToSelection(ScriptableObject asset, string assetName = null, bool @override = false)
        {
            if (null == asset)
            {
                Debug.LogWarning($"Asset is null. ");
                return;
            }

            var sInfo = EditorSelectionUtil.GetSelectionFileInfo();
            if (null == sInfo)
            {
                DebugUtil.LogWarning("Selection is null. ");
                return;
            }

            var unityDir = sInfo.IsFile ? sInfo.AssetPathParent : sInfo.AssetPath;
            if (string.IsNullOrEmpty(unityDir))
            {
                DebugUtil.LogWarning("Selection Dir is null. ");
                return;
            }

            assetName = GetAssetName(asset, assetName);
            var relativePath = GetAssetRelativePath(unityDir, assetName, @override);
            if (@override) AssetDatabase.DeleteAsset(relativePath);
            AssetDatabase.CreateAsset(asset, relativePath);
        }

        /// <summary>
        /// Generate ScriptableObject assets, set the save path, and optionally set a name
        /// 生成ScriptableObject资产, 指定保存路径, 可选择性指定名称
        /// </summary>
        /// <param name="relativeDir"></param>
        /// <param name="assetName"></param>
        /// <param name="override"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GenScriptableAsset<T>(string relativeDir, string assetName = null, bool @override = false)
            where T : ScriptableObject
        {
            var asset = ScriptableObject.CreateInstance<T>();
            if (null == asset)
            {
                Debug.LogWarning($"{typeof(T)} Undefined. ");
                return null;
            }

            GenScriptableAsset(asset, relativeDir, assetName, @override);
            return asset;
        }

        /// <summary>
        /// Generate ScriptableObject assets, set the save path, and optionally set a name
        /// 生成ScriptableObject资产, 指定保存路径, 可选择性指定名称
        /// </summary>
        /// <param name="asset"></param>
        /// <param name="relativeDir"></param>
        /// <param name="assetName"></param>
        /// <param name="override"></param>
        public static void GenScriptableAsset(ScriptableObject asset, string relativeDir, string assetName = null,
            bool @override = false)
        {
            if (null == asset)
            {
                Debug.LogWarning($"Asset is null. ");
                return;
            }

            InitDir(UnityPathUtil.UnityPath2AbsPath(relativeDir, false));
            assetName = GetAssetName(asset, assetName);
            var relativePath = GetAssetRelativePath(relativeDir, assetName, @override);
            if (@override) AssetDatabase.DeleteAsset(relativePath);

            //在指定路径下创建一个asset配置文件
            AssetDatabase.CreateAsset(asset, relativePath);
        }

        private static string GetAssetRelativePath(string unityDir, string assetName, bool @override)
        {
            var absDir = UnityPathUtil.UnityPath2AbsPath(unityDir, false);
            if (!@override)
            {
                assetName = UpgradeAssetName(absDir, assetName);
            }

            return UnityPathUtil.Format2UnityPath(Path.Combine(unityDir, assetName));
        }

        private static string GetAssetName(ScriptableObject asset, string assetName)
        {
            if (!string.IsNullOrEmpty(assetName)) return assetName;
            return $"{asset.GetType().Name}.asset";
        }

        private static string UpgradeAssetName(string absDir, string assetName)
        {
            var absPath = Path.Combine(absDir, assetName);
            if (!FileUtil.Exists(absPath)) return assetName;

            var shortName = PathUtil.ClearExtension(assetName);
            var extension = FileUtil.GetExtension(assetName);
            var id = 1;
            while (true)
            {
                var nextShortName = $"{shortName}_{id}";
                var nextFileName = string.IsNullOrEmpty(extension) ? nextShortName : $"{nextShortName}.{extension}";
                var nextAbsPath = Path.Combine(absDir, $"{nextFileName}");
                if (!FileUtil.Exists(nextAbsPath)) return nextFileName;
                id += 1;
            }
        }

        private static void InitDir(string absDir)
        {
            if (Directory.Exists(absDir)) return;
            //创建指定目录
            Directory.CreateDirectory(absDir);
        }

        private static void DeleteOldFile(string absFilePath)
        {
            FileUtil.DeleteFile(absFilePath, true);
        }
    }
}