
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using iHuman.UnitySz.Editor;
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

public class AppBuilder
{


    public static string AssetsRoot = Application.dataPath.Replace("\\", "/") + "/"; //F:/repos/ihuman-art/app/Assets/
    public static string projectRoot = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length).Replace("\\", "/");

    public static HashSet<string> gameDirs;

    [InitializeOnLoadMethod]
    static void Setup()
    {
        Debug.Log("AppBuilder Setup");
        SetupRes();
    }

    static void SetupRes(bool isExportModuleResList = false)
    {
        Debug.Log("AppBuilder SetupRes");
        ModuleResMgr.Instance.itemList.Clear();
        // pkg
        string[] pkgAssetsDirs = new string[] { "Assets/art/app/", "Assets/app/", "Assets/common/" };

        ModuleItem pkgItem = new("pkg", pkgAssetsDirs)
        {
            isInPkg = true
        };
        ModuleResMgr.Instance.itemList.Add(pkgItem);

        // webres
        string[] webresAssetsDirs = new string[] { "Assets/art/webres/" };
        ModuleItem webresItem = new("webres", webresAssetsDirs);
        ModuleResMgr.Instance.itemList.Add(webresItem);
        // 游戏的配置, 会以 root 下的子目录名作为 gameId, subdirs 是该游戏包含的目录
        // gameIdPrefix 是最终生成 moduleId 的时候会加到 gameId 前面
        List<(string root, List<string> subdirs, string gameIdPrefix)> gameConfig = new()
        {
            ("art/game/testgame", new List<string>{"Assets/art/game/testgame/{gameId}", "Assets/gamesrc/testgame/{gameId}"}, null),
            ("art/game/say", new List<string>{"Assets/art/game/say/{gameId}", "Assets/gamesrc/say/{gameId}", "Assets/art/game/say/common"}, null),
            ("art/game/practice", new List<string>{"Assets/art/game/practice/{gameId}", "Assets/gamesrc/practice/{gameId}"}, null),
            ("art/game/expand", new List<string>{"Assets/art/game/expand/{gameId}", "Assets/gamesrc/expand/{gameId}"}, null),
            ("art/game/gushi/travel", new List<string>{"Assets/art/game/gushi/travel/{gameId}",  "Assets/gamesrc/poetry/travel/{gameId}", "Assets/gamesrc/poetry/poetries/{gameId}"}, "gushi_travel"),
            ("art/game/gushi/through", new List<string>{"Assets/art/game/gushi/through/{gameId}", "Assets/gamesrc/poetry/through/{gameId}", "Assets/gamesrc/poetry/poetries/{gameId}"}, "gushi_through"),
            ("art/game/gushi/sing", new List<string>{"Assets/art/game/gushi/sing/{gameId}", "Assets/gamesrc/poetry/sing/{gameId}", "Assets/gamesrc/poetry/poetries/{gameId}"}, "gushi_sing"),
            ("art/game/gushi/say", new List<string>{"Assets/art/game/gushi/say/{gameId}", "Assets/gamesrc/poetry/say/{gameId}", "Assets/gamesrc/poetry/poetries/{gameId}"}, "gushi_say"),
            ("art/game/gushi/exercise", new List<string>{"Assets/art/game/gushi/exercise/{gameId}", "Assets/gamesrc/poetry/exercise/{gameId}", "Assets/gamesrc/poetry/poetries/{gameId}"}, "gushi_exercise"),
            ("art/game/weekly", new List<string>{"Assets/art/game/weekly/{gameId}", "Assets/gamesrc/weekly/{gameId}"}, null),
            ("art/game/monthly", new List<string>{"Assets/art/game/monthly/{gameId}"}, null),
        };
        foreach (var item in gameConfig)
        {
            if (Directory.Exists(AssetsRoot + item.root))
            {
                string[] gameSubDirectoryNames = Directory.GetDirectories(AssetsRoot + item.root).Where(d => Directory.EnumerateFileSystemEntries(d).Any()).Select(d => Path.GetFileName(d)).ToArray();
                var subdirs = item.subdirs; //new List<string>{"Assets/art/game/testgame/{gameId}", "Assets/gamesrc/testgame/{gameId}"}
                foreach (var gameId in gameSubDirectoryNames)
                {
                    bool endsWithInteger = Regex.IsMatch(gameId, @"\d+$");
                    if (!endsWithInteger)
                        continue;
                    string[] gameSubDirs = subdirs.Select(s => s.Replace("{gameId}", gameId)).ToArray();
                    string moduleId = (item.gameIdPrefix == null) ? gameId : item.gameIdPrefix + "_" + gameId;
                    ModuleItem gameItem = new(moduleId, gameSubDirs, false, false);
                    ModuleResMgr.Instance.itemList.Add(gameItem);
                    Debug.Log($"moduleId:{moduleId}, gameSubDirs:" + string.Join(", ", gameSubDirs));
                }
            }
        }
        // gamecommon

        string gushiArtPrefix = "Assets/art/game/gushi/";
        string gushiSrcPrefix = "Assets/gamesrc/poetry/";
        string practiceArtCommon = "Assets/art/game/practice/common";
        string practiceSrcCommon = "Assets/gamesrc/practice/common";
        List<(string id, List<string> subdirs)> gameCommonConfig = new()
        {
            ("practice0000", new List<string>{practiceArtCommon, practiceSrcCommon}),
            ("expand0000", new List<string>{"Assets/art/game/expand/common", "Assets/gamesrc/expand/common"}),
            ("gushi_travel_0000", new List<string>{$"{gushiArtPrefix}common", $"{gushiArtPrefix}travel/common", $"{gushiSrcPrefix}travel/common", $"{gushiSrcPrefix}common"}),
            ("gushi_through_0000", new List<string>{$"{gushiArtPrefix}common", $"{gushiArtPrefix}through/common", $"{gushiSrcPrefix}through/common", $"{gushiSrcPrefix}common"}),
            ("gushi_sing_0000", new List<string>{ $"{gushiArtPrefix}common", $"{gushiArtPrefix}sing/common", $"{gushiSrcPrefix}sing/common", $"{gushiSrcPrefix}common"}),
            ("gushi_say_0000", new List<string>{$"{gushiArtPrefix}common", $"{gushiArtPrefix}say/common", $"{gushiSrcPrefix}say/common", $"{gushiSrcPrefix}common"}),
            ("gushi_exercise_exercise0000", new List<string>{practiceArtCommon, $"{gushiArtPrefix}common", $"{gushiArtPrefix}exercise/common", $"{gushiSrcPrefix}exercise/common", $"{gushiSrcPrefix}common", practiceSrcCommon}),
            ("weekly0000", new List<string>{practiceArtCommon, "Assets/art/game/weekly/common", practiceSrcCommon, "Assets/gamesrc/weekly/common"}),
            ("monthly0000", new List<string>{"Assets/art/game/monthly/common", "Assets/gamesrc/monthly/common"}),
        };
        foreach (var (id, subdirs) in gameCommonConfig)
        {
            //游戏公共代码
            ModuleItem gameCommon = new(id, subdirs.ToArray(), false, false);
            ModuleResMgr.Instance.itemList.Add(gameCommon);
            Debug.Log($"gameCommonId:{id}, SubDirs:"+string.Join(", ", subdirs));
        }


        if (Directory.Exists(AssetsRoot + "art/book"))
        {
            // 绘本的配置
            string[] bookSubDirectoryNames = Directory.GetDirectories(AssetsRoot + "art/book")
            .Where(d => !Path.GetFileName(d).Equals(".svn", StringComparison.OrdinalIgnoreCase) && Directory.EnumerateFileSystemEntries(d).Any())
            .Select(d => Path.GetFileName(d))
            .ToArray();
            foreach (var bookId in bookSubDirectoryNames)
            {
                string[] bookSubDirs = new string[] { $"Assets/art/book/{bookId}" };
                ModuleItem bookItem = new($"book{bookId}", bookSubDirs, false, false);
                ModuleResMgr.Instance.itemList.Add(bookItem);
                Debug.Log($"bookId:{bookId}, bookSubDirs:" + string.Join(", ", bookSubDirs));
            }
        }
        //绘本公共代码
        ModuleItem bookCommon = new("book0000", new string[] { "Assets/gamesrc/book" }, false, false);
        ModuleResMgr.Instance.itemList.Add(bookCommon);
        Debug.Log($"bookId:book0000, bookSubDirs:Assets/gamesrc/book");

        gameDirs = new HashSet<string>(ModuleResMgr.Instance.itemList.Where(d => d.id != "pkg" && d.id != "webres").Select(d => d.dirList).SelectMany(d => d).Select(s => s.ToLower()).Select(d => d.EndsWith("/") ? d : d + "/"));
        Debug.Log("[AppBuilder]  gameDirs" + string.Join(", ", gameDirs));

        if (isExportModuleResList)
        {
            // 导出所有的 moduleids
            var moduleItems = ModuleResMgr.Instance.itemList;
            string content = string.Join("\n", moduleItems.Select(m => m.id).OrderBy(id => id));
            string file = Application.dataPath.Replace("\\", "/") + "/app/Editor/build/moduleResList.txt";
            File.WriteAllText(file, content);
        }


        SublistAction.handleGetSubKeyList = GetSubKeyList;
        SublistAction.handleIsAppSubKey = IsAppSubKey;
        AssetBundleName.handleGetAssetBundleName = GetAssetBundleName;
        AssetBundleName.useAutoABName = true;
        AssetBundleName.isOnlyReslinkSetAb = true;
        WebResGen.RootDir = "Assets/art/webres/";
        WebResGen.spineDirs = new string[] { "spine/" };

        BuildEnvAction.onChangeEnv = OnChangeEnv;
    }

    public static string[] GetSubKeyList(string abname)
    {
        string AB_SUFFIX = AssetBundleName.AB_SUFFIX;
        if (abname == "assets/launcher_unity.ab")
            return new string[] { "pkg" };

        if (abname.EndsWith("_luabytes" + AB_SUFFIX) || abname.EndsWith("_reslink" + AB_SUFFIX) || abname.EndsWith("_unity" + AB_SUFFIX) || abname.EndsWith("/game" + AB_SUFFIX) || abname.EndsWith("/lua" + AB_SUFFIX) || abname.EndsWith("/scene" + AB_SUFFIX))
        {
            List<string> retList = new();
            foreach (var item in ModuleResMgr.Instance.itemList)
            {
                if (item.isDirMatch(abname, false))
                {
                    retList.Add(item.id);
                }
            }
            if (retList.Count == 0)
                Debug.LogWarning($"abname:{abname} not match ModuleResMgr.Instance.itemList");
            return retList.ToArray();

        }
        ModuleItem webresItem = ModuleResMgr.Instance.getModuleItemById("webres");
        if (webresItem.isDirMatch(abname, false))
        {
            return new string[] { webresItem.id };
        }

        Debug.LogWarning($"abname:{abname} not match sublist");
        return null;
    }

    public static bool IsAppSubKey(string key)
    {
        ModuleItem moduleItem = ModuleResMgr.Instance.getModuleItemById(key);
        return moduleItem.isInPkg;
    }

    public static string GetAssetBundleName(string path)
    {
        // if (path.EndsWith(".unity") && path.StartsWith("assets/art/app/scenes/mainmap"))
        //     return "";

        ModuleItem webresItem = ModuleResMgr.Instance.getModuleItemById("webres");
        if (webresItem.isDirMatch(path))
        {
            if (WebResGen.spineDirs != null)
            {
                foreach (var item in WebResGen.spineDirs)
                {
                    string baseDir = (WebResGen.RootDir + item).ToLower();
                    if (AssetBundleName.PathMatch(path, out string abname, baseDir, 99))
                    {
                        return abname + AssetBundleName.AB_SUFFIX;
                    }
                }
            }
            if (path.EndsWith(".lua.bytes"))
                return null;

            return path + AssetBundleName.AB_SUFFIX;
        }

        foreach (var item in gameDirs)
        {
            if (path.StartsWith(item))
            {
                string name = path.EndsWith(".lua.bytes") ? "lua" : (path.EndsWith(".unity") ? "scene" : "game");
                string abname = item + name + AssetBundleName.AB_SUFFIX;
                Debug.Log($"[AppBuilder] GetAssetBundleName path:{path}, abname:{abname}");
                return abname;
            }
        }

        return null;
    }

    [MenuItem("Builder/RefreshModuleResList", false, 9002)]
    public static void RefreshModuleResList()
    {
        SetupRes(true);
    }


    public static void OnChangeEnv(string envName)
    {
        Debug.Log($"[AppBuilder]OnChangeEnv {envName}");
        string dbDir = Application.persistentDataPath + "/db";
        if (Directory.Exists(dbDir))
            Directory.Delete(dbDir, true);
    }
}