using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;

namespace TyphoonUnitySDK
{
    /// <summary>
    /// oppo mini 发布逻辑
    /// </summary>
    public class PublishOppoMini : IPublish
    {
        private const string BUILD_WEBGL_PROJECT_PATH = "typhoon_oppo/webgl";
        private const string EXPORT_WEBGL_PROJECT_PATH = "typhoon_oppo/webgl_oppo";

        private const string QUICK_GAME_PROJECT_PATH = "typhoon_oppo/quickgame";
        private const string CDN_RES_PATH = "typhoon_oppo/cnd_res";

        private static string
            BUILD_QUICK_GAME_PROJ_BAT =
                $"{Directory.GetParent(EXPORT_WEBGL_PROJECT_PATH).FullName}/build-proj.bat"; //构建quickgame工程批处理

        private static string BUILD_RELEASE_BAT =
            $"{Directory.GetParent(EXPORT_WEBGL_PROJECT_PATH).FullName}/build-release.bat"; //构建release包批处理


        private static string GetOppoMiniCliRootPathFullPath() =>
            Path.GetFullPath(PluginModuleInstaller.GetPluginRootPath(PluginModuleInstaller.PluginNames.OppoMiniGameCli))
                .Replace("/", "\\");

        /// <summary>
        /// 发布逻辑
        /// </summary>
        public void Publish(PublishSetting setting)
        {
            var result = new PublishResult();
            var config = OppoMiniConfig.Default;

            //不支持2020和2021以外的版本
#if !UNITY_2020 && !UNITY_2021
            UniEditor.ShowMessageBox("只支持Unity2020及Unity2021", null);
            return;
#endif

            if (string.IsNullOrWhiteSpace(config.PackageName))
            {
                UniEditor.ShowMessageBox("包名不可为空", null);
                return;
            }

            if (string.IsNullOrWhiteSpace(config.GameName))
            {
                UniEditor.ShowMessageBox("游戏名不可为空", null);
                return;
            }

            if (config.GameIcon == null)
            {
                UniEditor.ShowMessageBox("游戏ICON不可以为空", null);
                return;
            }

            //检查配置
            if (string.IsNullOrWhiteSpace(config.PrivatePem))
            {
                UniEditor.ShowMessageBox("preivate.pem 不可为空", null);
                return;
            }

            if (!File.Exists(config.PrivatePem))
            {
                UniEditor.ShowMessageBox($"找不到preivate.pem 路径:{config.PrivatePem}", null);
                return;
            }

            if (string.IsNullOrWhiteSpace(config.CertificatePem))
            {
                UniEditor.ShowMessageBox("certificate.pem 不可为空", null);
                return;
            }

            if (!File.Exists(config.CertificatePem))
            {
                UniEditor.ShowMessageBox($"找不到certificate.pem 路径:{config.CertificatePem}", null);
                return;
            }

            if (config.PrivacyPolicyImage == null)
            {
                UniEditor.ShowMessageBox($"隐私政策文案长图不可为空", null);
                return;
            }

            var path = GetAgeImagePath(config.AgeLevel);
            if (!File.Exists(path))
            {
                UniEditor.ShowMessageBox($"适龄提醒配置有误,请重新配置", null);
                return;
            }

            if (config.EnableTrack && string.IsNullOrWhiteSpace(config.UmaAppKey))
            {
                UniEditor.ShowMessageBox($"友盟appkey不可为空,请重新配置", null);
                return;
            }


            if (!PluginModuleInstaller.IsInstallOppoMiniGameCli())
            {
                UniEditor.ShowMessageBox("缺少oppo-minigame-cli,安装？\n(请等待安装完毕后再重试)",
                    () => { PluginModuleInstaller.InstallOppoMiniGameCliAsync(); });
                return;
            }

            //检查配置
            DoBuild(setting);
        }

        public void DoBuild(PublishSetting setting)
        {
            if (!Directory.Exists(BUILD_WEBGL_PROJECT_PATH))
            {
                Directory.CreateDirectory(BUILD_WEBGL_PROJECT_PATH);
            }

            BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, BUILD_WEBGL_PROJECT_PATH, BuildTarget.WebGL,
                BuildOptions.None);
            //组合工程
            CombineProj();
        }

        //组合工程
        public void CombineProj()
        {
            Debug.Log($"创建webgl_oppo：{BUILD_WEBGL_PROJECT_PATH}->{EXPORT_WEBGL_PROJECT_PATH}");
            UniEditor.CopyFolder(BUILD_WEBGL_PROJECT_PATH, EXPORT_WEBGL_PROJECT_PATH);
            var path = EXPORT_WEBGL_PROJECT_PATH;
            var config = OppoMiniConfig.Default;
            //处理wasm...
            if (Directory.Exists(path))
            {
                //删除旧cdn资源
                var cdnFolder = $"{CDN_RES_PATH}/v{config.VersionCode}";

                if (Directory.Exists(cdnFolder))
                {
                    UniEditor.DeleteFolder(cdnFolder);
                }

                //分离wasm
                SplitWasm();
                //复制StreamingAssets
                CopyStreamingAssets();

                {
                    //oppo-native.js
                    var from = "Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/oppo-native.js";
                    var to = $"{path}/Build/{Path.GetFileName(from)}";
                    Debug.Log($"复制{from}到{to}");
                    File.Copy(from, to, true);
                }

                //复制js到指定文件夹
                {
                    //typhoon-unity-oppo.js
                    var from = "Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/typhoon-unity-oppo.js";
                    var to = $"{path}/Build/{Path.GetFileName(from)}";
                    Debug.Log($"复制{from}到{to}");
                    File.Copy(from, to, true);
                }

                {
                    //typhoon-unity-oppo-config.js
                    var from = "Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/typhoon-unity-oppo-config.js";
                    var to = $"{path}/Build/{Path.GetFileName(from)}";
                    var code = File.ReadAllText(from);
                    code = code.Replace("$LIMIT_FPS_FLAG$", config.LimitFps ? "true" : "false");
                    code = code.Replace("$LIMIT_FPS$", config.FrameRate.ToString());
                    //广告参数
                    code = code.Replace("$BANNER_ENABLE$", config.BannerEnable.ToString().ToLower());
                    code = code.Replace("$BANNER_INTERVAL$", config.BannerInterval.ToString());
                    code = code.Replace("$BANNER_POS_ID$", $"\"{config.BannerPosId}\"");
                    code = code.Replace("$BANNER_BOTTOM$", config.BannerBottom ? "1" : "0");

                    code = code.Replace("$INTERS_ENABLE$", config.IntersEnable.ToString().ToLower());
                    code = code.Replace("$INTERS_COOL_DOWN$", config.IntersInterval.ToString());
                    code = code.Replace("$INTERS_POS_ID$", $"\"{config.IntersPosId}\"");

                    code = code.Replace("$VIDEO_ENABLE$", config.VideoEnable.ToString().ToLower());
                    code = code.Replace("$VIDEO_RESET_INTERS_COOL$", config.VideoResetIntersCool.ToString());
                    code = code.Replace("$VIDEO_POS_ID$", $"\"{config.VideoPosId}\"");

                    //隐私政策
                    var privacy = ""; //File.ReadAllText(AssetDatabase.GetAssetPath(config.PrivacyPolicyImage));
                    code = code.Replace("$PRIVACY_MESSAGE$", $"{privacy}");

                    //事件上报
                    code = code.Replace("$ENABLE_TRACK$", config.EnableTrack ? "1" : "0");
                    code = code.Replace("$UMA_APP_KEY$", config.UmaAppKey);

                    Debug.Log($"写入{to}");
                    File.WriteAllText(to, code);
                }

                {
                    //typhoon-mini-sdk-oppo.js
                    var from = "Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/typhoon-mini-sdk-oppo.js";
                    var to = $"{path}/Build/{Path.GetFileName(from)}";
                    Debug.Log($"复制{from}到{to}");
                    File.Copy(from, to, true);
                }

                
                {
                    //写入uma.min.js
                    var from = "Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/uma.min.js";
                    var to = $"{path}/Build/{Path.GetFileName(from)}";
                    var code = File.ReadAllText(from);
                    var pattern = @"export[\s]*{[\s]*ge[\s]*as[\s]*default[\s]*}[\s]*;";
                    var replacement = $"window['umaPlugin']=ge;";
                    code = Regex.Replace(code, pattern, replacement);
                    Debug.Log($"写入{to}");
                    File.WriteAllText(to, code);
                }
                

                //生成批处理
                CreateInstallBat();
                CreateReleaseBat();


                //删除quickgame工程
                if (Directory.Exists(QUICK_GAME_PROJECT_PATH))
                {
                    UniEditor.DeleteFolder(QUICK_GAME_PROJECT_PATH);
                }

                //构建quickgame工程
                UniEditor.RunBat(BUILD_QUICK_GAME_PROJ_BAT);

                if (!Directory.Exists(QUICK_GAME_PROJECT_PATH))
                {
                    throw new Exception($"找不到：{QUICK_GAME_PROJECT_PATH}");
                }

                //复制签名到指定目录
                var private_pem = $"{QUICK_GAME_PROJECT_PATH}/sign/release/private.pem";
                var certificate_pem = $"{QUICK_GAME_PROJECT_PATH}/sign/release/certificate.pem";
                if (!Directory.Exists(Path.GetDirectoryName(private_pem)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(private_pem));
                }

                File.Copy(config.PrivatePem, private_pem, true);
                File.Copy(config.CertificatePem, certificate_pem, true);


                var pathManifest = $"{QUICK_GAME_PROJECT_PATH}/manifest.json";
                if (!File.Exists(pathManifest))
                {
                    throw new Exception($"找不到：{pathManifest}");
                }

                Debug.Log("修改manifest.json");
                var json = File.ReadAllText(pathManifest);
                var manifest = json.ToXObject<Dictionary<string, object>>();

                try
                {
                    manifest["package"] = config.PackageName;
                    manifest["name"] = config.GameName;
                    manifest["versionName"] = config.VersionName;
                    manifest["versionCode"] = config.VersionCode;
                    manifest["orientation"] =
                        config.ScreenOrientation == Orientation.Portrait ? "portrait" : "landscape";
                    File.WriteAllText(pathManifest, manifest.ToXJson());
                }
                catch (Exception e)
                {
                    throw new Exception($"修改manifest失败：{e}");
                }

                //复制logo
                {
                    var pathTo = $"{QUICK_GAME_PROJECT_PATH}/logo.png";
                    File.Copy(AssetDatabase.GetAssetPath(config.GameIcon), pathTo, true);
                }


                var age = (int)config.AgeLevel;
                var ageImage = $"{UniEditor.PathRoot}/Editor/Texture/age_{age}.png"; //适龄图片
                //复制适龄图片
                {
                    var pathTo = $"{QUICK_GAME_PROJECT_PATH}/age.png";
                    File.Copy(ageImage, pathTo, true);
                }

                //创建代码main.js
                {
#if UNITY_2019
                    WriteMainJs_2019();
#endif

#if UNITY_2020
                    WriteMainJs_2020();
#endif

#if UNITY_2021
                    WriteMainJs_2021();
#endif
                }


                Debug.Log("发布release rpk");
                UniEditor.RunBat(BUILD_RELEASE_BAT);

                var pathReleaseRpk = $"{QUICK_GAME_PROJECT_PATH}/dist/{config.PackageName}.signed.rpk";
                if (!File.Exists(pathReleaseRpk))
                {
                    throw new Exception($"发布失败，找不到:{pathReleaseRpk}");
                }

                Debug.Log($"发布release rpk 成功,路径:{pathReleaseRpk}");
                //打开发布目录
                EditorUtility.RevealInFinder(pathReleaseRpk);
                var pathWasmZip = $"{CDN_RES_PATH}/v{config.VersionCode}/wasm.zip";
                var streamingAssetsPath = $"{CDN_RES_PATH}/v{config.VersionCode}/StreamingAssets";
                if (File.Exists(pathWasmZip))
                {
                    //打开cdn资源地址
                    Debug.Log($"打开cdn资源目录:{pathWasmZip}");
                    EditorUtility.RevealInFinder(pathWasmZip);
                    //写入使用说明
                    var sb = new StringBuilder();
                    sb.AppendLine($"将此文件夹的所有资源上传到cdn:{config.GetFinalCDN()}");
                    sb.AppendLine($"形成最终路径如：");
                    sb.AppendLine($"{config.GetFinalCDN()}/wasm.zip");
                    sb.AppendLine($"{config.GetFinalCDN()}/<文件夹>/<文件名>...");
                    if (Directory.Exists(streamingAssetsPath))
                    {
                        sb.AppendLine($"{config.GetFinalCDN()}/StreamingAssets");
                    }

                    var readme = $"{Path.GetDirectoryName(pathWasmZip)}/使用说明.txt";
                    File.WriteAllText(readme, sb.ToString());
                }
            }
        }

        //切分wasm
        public void SplitWasm()
        {
            var config = OppoMiniConfig.Default;
            var cdn_res_folder = $"{CDN_RES_PATH}/v{config.VersionCode}";
            if (!Directory.Exists(cdn_res_folder))
            {
                Directory.CreateDirectory(cdn_res_folder);
            }

            var wasm_zip = $"{cdn_res_folder}/wasm.zip";
            var webgl_data = $"{EXPORT_WEBGL_PROJECT_PATH}/Build/webgl.data";
            var webgl_wasm = $"{EXPORT_WEBGL_PROJECT_PATH}/Build/webgl.wasm";
#if UNITY_2019
            //处理2019版本
             webgl_data = $"{EXPORT_WEBGL_PROJECT_PATH}/Build/webgl.data.unityweb";
             webgl_wasm = $"{EXPORT_WEBGL_PROJECT_PATH}/Build/webgl.wasm.code.unityweb";

            //修改webgl.json
            var webgl_json = $"{EXPORT_WEBGL_PROJECT_PATH}/Build/webgl.json";
            if (File.Exists(webgl_json))
            {
                var json = File.ReadAllText(webgl_json);
                var pattern = @"""dataUrl""\s*:\s*""([\w.])*""";
                var overrideWrite1 = $"\"dataUrl\": \"qgfile://usr/webgl.data.unityweb\"";
                json = Regex.Replace(json, pattern, overrideWrite1);
                var pattern2 = @"""wasmCodeUrl""\s*:\s*""([\w.])*""";
                var overrideWrite2 = $"\"wasmCodeUrl\": \"qgfile://usr/webgl.wasm.code.unityweb\"";
                json = Regex.Replace(json, pattern2, overrideWrite2);
                var map = json.ToXObject<Dictionary<string, object>>();
                map.Add("streamingAssetsUrl", $"{config.GetFinalCDN()}/StreamingAssets");
                File.WriteAllText(webgl_json, map.ToXJson());
            }
#endif
            if (File.Exists(webgl_data) && File.Exists(webgl_wasm))
            {
                //压缩到wasm.zip
                ZipTool.Zip(wasm_zip, new Dictionary<string, string>()
                {
                    { $"{webgl_data}", null },
                    { $"{webgl_wasm}", null },
                });
                //删除旧文件
                File.Delete(webgl_data);
                File.Delete(webgl_wasm);
            }
        }


        //复制StreamingAssets
        public void CopyStreamingAssets()
        {
            var config = OppoMiniConfig.Default;
            var cdn_res_folder = $"{CDN_RES_PATH}/v{config.VersionCode}";
            var pathStreamingAssets = $"{EXPORT_WEBGL_PROJECT_PATH}/StreamingAssets";
            if (Directory.Exists(pathStreamingAssets))
            {
                //加入addressableUrl,复制StreamingAssets到cdn资源中
                UniEditor.CopyFolder(pathStreamingAssets, $"{cdn_res_folder}/StreamingAssets");
            }
        }

        //生成安装批处理
        private static void CreateInstallBat()
        {
            if (Directory.Exists(EXPORT_WEBGL_PROJECT_PATH))
            {
                //webgl工程
                var cdn = OppoMiniConfig.Default.GetFinalCDN();
                var webglPath = Path.GetFullPath(EXPORT_WEBGL_PROJECT_PATH).Replace("/", "\\");
                var quickgame = $"{GetOppoMiniCliRootPathFullPath()}\\@oppo-minigame\\cli\\lib\\bin\\quickgame";
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"cd /d \"{webglPath}\"");
                sb.AppendLine($"\"{quickgame}\" unity --unityVer {Application.unityVersion} --addressable \"{cdn}\"");
                File.WriteAllText(BUILD_QUICK_GAME_PROJ_BAT, sb.ToString());
            }
        }

        //生成release批处理
        private static void CreateReleaseBat()
        {
            if (Directory.Exists(EXPORT_WEBGL_PROJECT_PATH))
            {
                //webgl工程
                var webglPath = Path.GetFullPath(EXPORT_WEBGL_PROJECT_PATH).Replace("/", "\\");
                var parentPath = Directory.GetParent(webglPath)?.FullName.Replace("/", "\\");
                var quickgameFolder = $"{parentPath}\\quickgame";
                var quickgame = $"{GetOppoMiniCliRootPathFullPath()}\\@oppo-minigame\\cli\\lib\\bin\\quickgame";
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"@echo build release...");
                sb.AppendLine($"@echo off");
                sb.AppendLine($"if exist \"{quickgameFolder}\\sign\\release\\private.pem\" (");
                sb.AppendLine($"echo quickgame exist, start build release...");
                sb.AppendLine($"cd /d {quickgameFolder}");
                sb.AppendLine($"{quickgame} pack release");
                sb.AppendLine($") else (");
                sb.AppendLine($" echo error! quickgame proj not exist");
                sb.AppendLine($"pause");
                sb.AppendLine($")");
                File.WriteAllText(BUILD_RELEASE_BAT, sb.ToString());
            }
        }


        //2020
        private static void WriteMainJs_2020()
        {
            var config = OppoMiniConfig.Default;
            Debug.Log("重写代码main.js---Unity.2020");
            var pathMainJs = $"Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/main_unity2020.js";
            var code = File.ReadAllText(pathMainJs);
            var hash = DateTime.Now.ToString($"yyyyMMdd-HHmmss-{Random.Range(100000, 999999)}"); //wasm.zip哈希码
            code = code.Replace("$CEHCCK_HASH_CODE$", hash);
            code = code.Replace("$WASM_ZIP_URL$", $"{config.GetFinalCDN()}/wasm.zip");
            code = code.Replace("$STREAMING_ASSETS_URL$", $"{config.GetFinalCDN()}/StreamingAssets");
            var pathMainJsTo = $"{QUICK_GAME_PROJECT_PATH}/main.js";
            File.WriteAllText(pathMainJsTo, code);
        }


        //2021
        private static void WriteMainJs_2021()
        {
            var config = OppoMiniConfig.Default;
            Debug.Log("重写代码main.js---Unity.2021");
            var pathMainJs = $"Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/main_unity2021.js";
            var code = File.ReadAllText(pathMainJs);
            var hash = DateTime.Now.ToString($"yyyyMMdd-HHmmss-{Random.Range(100000, 999999)}"); //wasm.zip哈希码
            code = code.Replace("$CEHCCK_HASH_CODE$", hash);
            code = code.Replace("$WASM_ZIP_URL$", $"{config.GetFinalCDN()}/wasm.zip");
            code = code.Replace("$STREAMING_ASSETS_URL$", $"{config.GetFinalCDN()}/StreamingAssets");
            var pathMainJsTo = $"{QUICK_GAME_PROJECT_PATH}/main.js";
            File.WriteAllText(pathMainJsTo, code);
        }


        private static void WriteMainJs_2019()
        {
            var config = OppoMiniConfig.Default;
            Debug.Log("重写代码main.js---Unity.2019");
            var pathMainJs = $"Assets/Typhoon_Gen/TyphoonSDK/Runtime/OppoMini/Editor/main_unity2019.js";
            var code = File.ReadAllText(pathMainJs);
            var hash = DateTime.Now.ToString($"yyyyMMdd-HHmmss-{Random.Range(100000, 999999)}"); //wasm.zip哈希码
            code = code.Replace("$CEHCCK_HASH_CODE$", hash);
            code = code.Replace("$WASM_ZIP_URL$", $"{config.GetFinalCDN()}/wasm.zip");
            var pathMainJsTo = $"{QUICK_GAME_PROJECT_PATH}/main.js";
            File.WriteAllText(pathMainJsTo, code);
        }

        private string GetAgeImagePath(AgeLevel ageLevel)
        {
            return $"{UniEditor.PathRoot}/Editor/Texture/age_{(int)ageLevel}.png";
        }
    }
}