using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEngine.Assertions;
using System.Security.Cryptography;
using System.Text;
using UGCTools.Runtime;
using System;

public class AssetBundleBuilder
{
    private static string assetBundleBuildOutput = "../DEETools/Builder/AB/";
    public static void CollectAllAssetBundles(string assetBundleDirectory, out AssetBundleBuild[] assetBundleBuildsArray)
    {
        UnityEngine.Object[] selectedAssets = Selection.objects;
        if (selectedAssets.Length == 0)
        {
            Debug.LogWarning("No assets selected for AssetBundle building.");
            assetBundleBuildsArray = null;
            return;
        }

        List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();

        foreach (UnityEngine.Object asset in selectedAssets)
        {
            string assetPath = AssetDatabase.GetAssetPath(asset);
            string assetBundleName = asset.name.ToLower() + ".ab";

            AssetBundleBuild build = new AssetBundleBuild
            {
                assetBundleName = assetBundleName,
                assetNames = new string[] { assetPath }
            };

            assetBundleBuilds.Add(build);
        }
        assetBundleBuildsArray = assetBundleBuilds.ToArray();
    }

    public static void CollectAllAssetBundles(UnityEngine.Object[] assets, out AssetBundleBuild[] assetBundleBuildsArray, BuildTarget buildTarget, string[] hashCodes, long timeStamp)
    {
        List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();
        foreach (UnityEngine.Object asset in assets)
        {
            string assetName = asset.name;
            string hasCode = string.Empty;
            if (asset is AnimationClip)
            {
                assetName = "animation";
                hasCode = hashCodes[0];
            }
            else if (asset is AudioClip)
            {
                assetName = "audio";
                hasCode = hashCodes[1];
            }
            else if (asset is Texture2D)
            {
                assetName = "image";
                hasCode = hashCodes[2];
            }
            string assetBundleName = $"{assetName}_{hasCode}_{timeStamp}.ab";
            AssetBundleBuild build = new AssetBundleBuild
            {
                assetBundleName = assetBundleName,
                assetNames = new string[] { AssetDatabase.GetAssetPath(asset) }
            };

            assetBundleBuilds.Add(build);
        }
        assetBundleBuildsArray = assetBundleBuilds.ToArray();
    }

    //[MenuItem("DEETools/Build AssetBundles/StandaloneWindows")]
    //public static void BuildStandaloneWindowsAssetBundles()
    //{
    //    string assetBundleDirectory = "Assets/UGC/ab";
    //    if (!System.IO.Directory.Exists(assetBundleDirectory))
    //    {
    //        System.IO.Directory.CreateDirectory(assetBundleDirectory);
    //    }

    //    CollectAllAssetBundles(assetBundleDirectory, out AssetBundleBuild[] assetBundleBuildsArray);

    //    BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.StandaloneWindows);

    //    Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
    //}

    //[MenuItem("DEETools/Build AssetBundles/WebGL")]
    //public static void BuildWebGLBundles()
    //{
    //    string assetBundleDirectory = "Assets/UGC/ab";
    //    if (!System.IO.Directory.Exists(assetBundleDirectory))
    //    {
    //        System.IO.Directory.CreateDirectory(assetBundleDirectory);
    //    }

    //    CollectAllAssetBundles(assetBundleDirectory, out AssetBundleBuild[] assetBundleBuildsArray);

    //    BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.WebGL);

    //    Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
    //}

    //[MenuItem("DEETools/Build AssetBundles/Android")]
    //public static void BuildAndroidBundles()
    //{
    //    string assetBundleDirectory = "Assets/UGC/ab";
    //    if (!System.IO.Directory.Exists(assetBundleDirectory))
    //    {
    //        System.IO.Directory.CreateDirectory(assetBundleDirectory);
    //    }

    //    CollectAllAssetBundles(assetBundleDirectory, out AssetBundleBuild[] assetBundleBuildsArray);

    //    BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android);

    //    Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
    //}

    //[MenuItem("DEETools/Extract AnimationClip")]
    //public static void ExtractAnimationClip()
    //{
    //    string fbxPath = AssetDatabase.GetAssetPath(Selection.activeObject);
    //    AnimationClip[] animationClips = AnimationUtility.GetAnimationClips(AssetDatabase.LoadAssetAtPath<GameObject>(fbxPath));
    //    if (animationClips.Length == 0)
    //    {
    //        Debug.LogWarning("No animation clips found in the fbx file.");
    //        return;
    //    }
    //    string fbxName = Path.GetFileNameWithoutExtension(fbxPath);
    //    string fbxDirectory = Path.GetDirectoryName(fbxPath);
    //    string fbxAssetPath = Path.Combine(fbxPath, fbxName);
    //    string animationDirectory = Path.Combine(fbxDirectory, fbxName + "_Animations");
    //    if (!Directory.Exists(animationDirectory))
    //    {
    //        Directory.CreateDirectory(animationDirectory);
    //    }
    //    foreach (AnimationClip clip in animationClips)
    //    {
    //        string clipPath = Path.Combine(animationDirectory, clip.name + ".anim");
    //        AssetDatabase.CreateAsset(clip, clipPath);
    //    }
    //    Debug.Log("All animation clips extracted to " + animationDirectory);
    //}

    public static void UGCBuildAllAssetBundle(ProjectSetting setting, ref string animationHashCode, ref string audioHashCode, ref string coverHashCode, ref long timeStamp)
    {
        string projectname = Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(setting));
        string buildDirectory = Path.Combine(Application.dataPath, assetBundleBuildOutput, projectname);
        if (!Directory.Exists(buildDirectory))
        {
            Directory.CreateDirectory(buildDirectory);
        }
        //TextAsset jsonAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(Path.Combine("Assets/DEETools/Res/Context", projectname, projectname + "_context.json"));
        //Assert.IsNotNull(jsonAsset, $"Json file not found.path:{Path.Combine("Assets/DEETools/Res/Context", projectname, projectname + "_context.json")}");
        AnimationClip animationClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(AssetDatabase.GUIDToAssetPath(setting.outputClipGuid));
        Assert.IsNotNull(animationClip, $"AnimationClip not found.path:{AssetDatabase.GUIDToAssetPath(setting.outputClipGuid)}");
        AudioClip audioClip = AssetDatabase.LoadAssetAtPath<AudioClip>(AssetDatabase.GUIDToAssetPath(setting.audioClipGuid));
        Assert.IsNotNull(audioClip, $"AudioClip not found.path:{AssetDatabase.GUIDToAssetPath(setting.audioClipGuid)}");
        Texture2D coverImage = AssetDatabase.LoadAssetAtPath<Texture2D>(AssetDatabase.GUIDToAssetPath(setting.audioConfig.coverImageGuid));
        Assert.IsNotNull(coverImage, $"CoverImage not found.path:{AssetDatabase.GUIDToAssetPath(setting.audioConfig.coverImageGuid)}");
        //Build StandaloneWindows AssetBundles
        string assetBundleDirectory = Path.Combine(Application.dataPath, assetBundleBuildOutput, projectname, System.Enum.GetName(typeof(BuildTarget), BuildTarget.StandaloneWindows));
        if (Directory.Exists(assetBundleDirectory))
        {
            Directory.Delete(assetBundleDirectory, true);
        }
        Directory.CreateDirectory(assetBundleDirectory);
        CollectAllAssetBundles(new UnityEngine.Object[] { animationClip, audioClip, coverImage }, out AssetBundleBuild[] assetBundleBuildsArray0, BuildTarget.StandaloneWindows, new string[] { animationHashCode, audioHashCode, coverHashCode }, timeStamp);
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray0, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.StandaloneWindows);
        Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
        //Build Android AssetBundles
        assetBundleDirectory = Path.Combine(Application.dataPath, assetBundleBuildOutput, projectname, System.Enum.GetName(typeof(BuildTarget), BuildTarget.Android));
        if (Directory.Exists(assetBundleDirectory))
        {
            Directory.Delete(assetBundleDirectory, true);
        }
        Directory.CreateDirectory(assetBundleDirectory);
        CollectAllAssetBundles(new UnityEngine.Object[] { animationClip, audioClip, coverImage }, out AssetBundleBuild[] assetBundleBuildsArray1, BuildTarget.Android, new string[] { animationHashCode, audioHashCode, coverHashCode }, timeStamp);
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray1, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android);
        Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
        //Build WebGL AssetBundles
        assetBundleDirectory = Path.Combine(Application.dataPath, assetBundleBuildOutput, projectname, System.Enum.GetName(typeof(BuildTarget), BuildTarget.WebGL));
        if (Directory.Exists(assetBundleDirectory))
        {
            Directory.Delete(assetBundleDirectory, true);
        }
        Directory.CreateDirectory(assetBundleDirectory);
        CollectAllAssetBundles(new UnityEngine.Object[] { animationClip, audioClip, coverImage }, out AssetBundleBuild[] assetBundleBuildsArray2, BuildTarget.WebGL, new string[] { animationHashCode, audioHashCode, coverHashCode }, timeStamp);
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuildsArray2, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.WebGL);
        Debug.Log("AssetBundles built and saved to " + assetBundleDirectory);
    }

    public static string CalculateMD5(string filePath)
    {
        using (var md5 = MD5.Create())
        {
            using (var stream = File.OpenRead(filePath))
            {
                var hash = md5.ComputeHash(stream);
                return System.BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
            }
        }
    }

    public static void ExtraAudioConfig(ProjectSetting setting, out string animationHashCode, out string audioHashCode, out string coverHashCode, out long timeStamp)
    {
        AudioContext audioContext = new AudioContext();
        string coverImagePath = AssetDatabase.GUIDToAssetPath(setting.audioConfig.coverImageGuid);
        audioContext.coverImageName = "image" + Path.GetExtension(coverImagePath);
        audioContext.musicName = setting.audioConfig.musicName;
        audioContext.singerName = setting.audioConfig.singerName;
        audioContext.musicStarLevel = setting.audioConfig.musicStarLevel;
        audioContext.musicBpm = setting.audioConfig.musicBpm;
        audioContext.musicStartTime = setting.audioConfig.musicStartTime;
        audioContext.musicLength = setting.audioConfig.musicLength;
        audioContext.musicType = setting.audioConfig.musicType;
        audioContext.startTime = setting.audioConfig.startTime;
        audioContext.endTime = setting.audioConfig.endTime;
        audioContext.speed = setting.audioConfig.speed;
        audioContext.exerciseIntensity = setting.audioConfig.exerciseIntensity;
        audioContext.musicId = SnowflakeIdGenerator.Instance.NextId();
        string audioPath = AssetDatabase.GUIDToAssetPath(setting.audioClipGuid);
        audioPath = audioPath.Substring(7);
        audioContext.hashCode = CalculateMD5(Path.Combine(Application.dataPath, audioPath));
        audioHashCode = audioContext.hashCode;
        Debug.Log($"audio hashCode:{audioContext.hashCode}");
        string imagePath = AssetDatabase.GUIDToAssetPath(setting.audioConfig.coverImageGuid);
        imagePath = imagePath.Substring(7);
        audioContext.imageHashCode = CalculateMD5(Path.Combine(Application.dataPath, imagePath));
        coverHashCode = audioContext.imageHashCode;

        AnimationContext animationContext = new AnimationContext();
        animationContext.startTime = setting.animatinConfig.startTime;
        animationContext.endTime = setting.animatinConfig.endTime;
        animationContext.length = setting.animatinConfig.endTime - setting.animatinConfig.startTime;
        animationContext.speed = setting.animatinConfig.speed;
        animationContext.ikOnFoot = setting.animatinConfig.enableFootIK;
        string animationPath = AssetDatabase.GUIDToAssetPath(setting.outputClipGuid);
        animationPath = animationPath.Substring(7);
        animationContext.hashCode = CalculateMD5(Path.Combine(Application.dataPath, animationPath));
        animationHashCode = animationContext.hashCode;

        timeStamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        UGCContextConfig ugcContextConfig = new UGCContextConfig
        {
            audioContext = audioContext,
            animationName = "animation.clip",
            audioName = "audio" + Path.GetExtension(audioPath),
            timeStamp = timeStamp,
            animationContext = animationContext,
        };
        string projectname = Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(setting));
        string json = JsonUtility.ToJson(ugcContextConfig);
        string buildDirectory = Path.Combine(Application.dataPath, "../DEETools/Builder/Context", projectname);
        if (!Directory.Exists(buildDirectory))
        {
            Directory.CreateDirectory(buildDirectory);
        }
        string jsonPath = Path.Combine(buildDirectory, "info.bytes");
        Debug.Log("output json:" + json);
        byte[] jsonBytes = SimpleEncryptor.Encrypt(Encoding.UTF8.GetBytes(json));
        File.WriteAllBytes(jsonPath, jsonBytes);
        string jsonStr = Encoding.UTF8.GetString(SimpleEncryptor.Decrypt(jsonBytes));
        File.WriteAllText(Path.Combine(buildDirectory, "info.json"), jsonStr);
    }
}
