﻿using Harmony12;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityModManagerNet;

namespace BaseResourceMod
{
    public class Settings : UnityModManager.ModSettings
    {
        /// <summary>保存原始配置文件</summary>
        public bool save_config = false;
        /// <summary>启动时增量载入配置文件</summary>
        public bool load_custom_config = true;
        /// <summary>将加载配置文件的详细信息记录到日志</summary>
        public bool detailed_custom_config_log = false;
        /// <summary>启动时载入外部贴图</summary>
        public bool load_custom_texture = true;
        /// <summary>将加载贴图文件的详细信息记录到日志</summary>
        public bool detailed_custom_texture_log = false;
        /// <summary>是否保存基础Sprite</summary>
        public bool save_common_sprite = false;
        /// <summary>是否保存蛐蛐图像</summary>
        public bool save_ququ = false;
        /// <summary>是否保存人物纸娃娃图像</summary>
        public bool save_avatar = false;
        /// <summary>是否保存各类地形图像</summary>
        public bool save_maptile = false;
        /// <summary>是否保存战斗背景</summary>
        public bool save_battleBack = false;

        public override void Save(UnityModManager.ModEntry modEntry)
        {
            Save(this, modEntry);
        }

    }
    public static class Main
    {
        internal static bool enabled;
        internal static Settings settings;
        internal static UnityModManager.ModEntry.ModLogger Logger;
        /// <summary>数据导出路径</summary>
        public const string backupdir = "./Backup/txt/";
        /// <summary>贴图导出路径</summary>
        public const string backupimgdir = "./Backup/Texture/";
        /// <summary>自定义数据导入路径</summary>
        public const string resdir = "./Data/";
        /// <summary>自定义贴图导入路径</summary>
        public const string imgresdir = "./Texture/";

        internal static readonly Dictionary<string, string> mods_res_dict = new Dictionary<string, string>();
        internal static readonly Dictionary<string, string> mods_sprite_dict = new Dictionary<string, string>();
        internal static GetSpritesInfoAsset getSpritesInfoAsset;
        /// <summary>保存自定义的sprite路径信息</summary>
        // 使用ValueTuple避免创建过多小Object, 需要注意ValueTuple是value type
        internal static readonly Dictionary<string, ValueTuple<string, Sprite>> customSpriteInfosDic = new Dictionary<string, ValueTuple<string, Sprite>>();
        /// <summary>待导出的sprite数目</summary>
        internal static int spriteCounter;
        /// <summary>index: 0. 需要载入的txt配置文件数目；1.成功载入的txt配置文件数目</summary>
        internal static int[] csvFilesCounter = new int[2];
        /// <summary>index: 0. 需要载入的外部贴图文件数目；1.成功载入的外部贴图文件数目</summary>
        internal static int[] imageFilesCounter = new int[2];


        public static bool Load(UnityModManager.ModEntry modEntry)
        {
            if (!Directory.Exists(backupdir))
            {
                Directory.CreateDirectory(backupdir);
            }

            Logger = modEntry.Logger;
            settings = UnityModManager.ModSettings.Load<Settings>(modEntry);
            modEntry.OnToggle = OnToggle;
            modEntry.OnGUI = OnGUI;
            modEntry.OnSaveGUI = OnSaveGUI;
            // 动态加载贴图类
            DynamicSetSprite dynamicSetSprites = SingletonObject.getInstance<DynamicSetSprite>();
            // 游戏贴图信息类
            getSpritesInfoAsset = (GetSpritesInfoAsset)Traverse.Create(dynamicSetSprites).Field("gsInfoAsset").GetValue();
            HarmonyInstance.Create(modEntry.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
            return true;
        }
        /// <summary>
        /// 从基础资源框架MOD中导入自定义数据
        /// </summary>
        /// <param name="modEntry"></param>
        /// <param name="respath">外部数据路径</param>
        public static void registModResDir(UnityModManager.ModEntry modEntry, string respath)
        {
            mods_res_dict[modEntry.Info.DisplayName] = respath;
        }
        /// <summary>
        /// 从基础资源框架MOD中导入自定义贴图
        /// </summary>
        /// <param name="modEntry"></param>
        /// <param name="spritepath">外部贴图路径</param>
        public static void registModSpriteDir(UnityModManager.ModEntry modEntry, string spritepath)
        {
            mods_sprite_dict[modEntry.Info.DisplayName] = spritepath;
        }
        /// <summary>
        /// 从基础资源框架MOD中导入自定义数据和贴图
        /// </summary>
        /// <param name="modEntry"></param>
        /// <param name="respath">外部数据路径</param>
        /// <param name="spritepath">外部贴图路径</param>
        public static void registModResourceDir(UnityModManager.ModEntry modEntry, string respath, string spritepath)
        {
            mods_res_dict[modEntry.Info.DisplayName] = respath;
            mods_sprite_dict[modEntry.Info.DisplayName] = spritepath;
        }

        private static bool OnToggle(UnityModManager.ModEntry modEntry, bool value)
        {
            if (!value)
            {
                return false;
            }

            enabled = value;

            return true;
        }

        private static void OnGUI(UnityModManager.ModEntry modEntry)
        {
            GUILayout.BeginVertical("Box");
            {
                GUILayout.Label("基础资源框架：");
                GUILayout.Label($"<color=#F28234>当前的游戏根目录:{Environment.CurrentDirectory}</color>");
                // 基本设置
                GUILayout.BeginVertical("Box");
                {
                    settings.load_custom_config = GUILayout.Toggle(settings.load_custom_config, $"启动时增量载入 游戏 根目录下 <color=#8FBAE7>{resdir}</color> 的<color=#F28234>子文件夹</color>内的配置文件");
                    GUILayout.Label("<color=#F28234>注意： 只有放置在<color=#F28234>子文件夹</color>内的配置文件才会增量载入: 例如<color=#8FBAE7>{resdir}</color>/abcd/Item_Date.txt.001.txt");
                    GUILayout.Label("自定义配置文件命名方式形如 Item_date.txt.001.txt  其中数字如 001 为加载顺序，从001开始顺序加载，最后加载不带数字后缀的文件，详情见更多信息。");
                    settings.load_custom_texture = GUILayout.Toggle(settings.load_custom_texture, $"启动时载入 游戏 根目录下 <color=#8FBAE7>{imgresdir}</color> 内的贴图");
                    GUILayout.Label($"自定义贴图目录结构设置方法参见更多信息。");
                }
                GUILayout.EndVertical();
                // 更多信息
                GUILayout.BeginHorizontal("box");
                {
                    GUILayout.Label("更多信息参见:", GUILayout.ExpandWidth(false));
                    if (GUILayout.Button("https://github.com/phorcys/Taiwu_mods/tree/master/BaseResourceMod"))
                    {
                        Application.OpenURL("https://github.com/phorcys/Taiwu_mods/tree/master/BaseResourceMod");
                    }
                }
                GUILayout.EndHorizontal();
                // 结果统计
                GUILayout.BeginVertical("Box");
                {
                    GUILayout.Label("载入结果统计:");
                    GUILayout.Label($" 配置文件：<color=#8FBAE7>{resdir}</color> 中共有<color=#F28234>{csvFilesCounter[0]}</color>个txt文件，实际载入<color=#F28234>{csvFilesCounter[1]}</color>个txt文件，欲知详情请勾选\"将加载配置文件的详细信息记录到日志\"并重新启动游戏");
                    GUILayout.Label($" 外部贴图：<color=#8FBAE7>{imgresdir}</color> 中共有<color=#F28234>{imageFilesCounter[0]}</color>个png文件, 实际载入<color=#F28234>{imageFilesCounter[1]}</color>个png文件，欲知详情请勾选\"将加载贴图文件的详细信息记录到日志\"并重新启动游戏");
                }
                GUILayout.EndVertical();
                // 日志
                GUILayout.BeginVertical("Box");
                {
                    GUILayout.Label("日志：(用于查看哪些文件载入/替换成功)");
                    if (settings.load_custom_config)
                    {
                        GUILayout.BeginVertical("Box");
                        settings.detailed_custom_config_log = GUILayout.Toggle(settings.detailed_custom_config_log, "将加载配置文件的详细信息记录到日志（开始游戏时载入速度可能会变慢）");
                        GUILayout.EndVertical();
                    }
                    if (settings.load_custom_texture)
                    {
                        GUILayout.BeginVertical("Box");
                        settings.detailed_custom_texture_log = GUILayout.Toggle(settings.detailed_custom_texture_log, "将加载贴图文件的详细信息记录到日志（开始游戏时载入速度可能会变慢）");
                        GUILayout.EndVertical();
                    }
                    if (GUILayout.Button("打开日志文件", GUILayout.ExpandWidth(false)))
                    {
                        Process.Start($"{UnityModManager.modsPath}\\UnityModManager.log");
                    }
                }
                GUILayout.EndVertical();
                // 调试选项
                GUILayout.BeginVertical("Box");
                {
                    GUILayout.Label("<color=#F28234>以下为调试开发增量MOD和美化MOD选项，正常游戏请不要使用</color>");
                    GUILayout.BeginVertical("Box");
                    {
                        settings.save_config = GUILayout.Toggle(settings.save_config, $"<color=#F28234>游戏启动时</color>保存原始配置文件到游戏 根目录下的 <color=#8FBAE7>{backupdir}</color> 目录下");
                        GUILayout.Label("开启后游戏启动时(<color=#8FBAE7>跟下面的保存按钮无关</color>)，mod会保存当前版本游戏配置文件到 Backup/txt 目录下，txt为原始csv文件，json为解析后的游戏内配置数据");
                    }
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical("box");
                    {
                        GUILayout.Label("导出游戏贴图(Sprites)：");
                        GUILayout.Label($"将游戏中当前版本的Sprite保存到游戏根目录下的<color=#8FBAE7>{backupimgdir}</color>目录下，格式为PNG图片。\n<color=#F28234>注意: 会删除该目录下的所有文件!</color>");
                        settings.save_common_sprite = GUILayout.Toggle(settings.save_common_sprite, $"是否保存基础Sprite");
                        settings.save_ququ = GUILayout.Toggle(settings.save_ququ, "是否保存 蛐蛐图像 （注意，很大，很慢）");
                        settings.save_avatar = GUILayout.Toggle(settings.save_avatar, "是否保存 人物纸娃娃图像 （注意，很大，很慢）");
                        settings.save_maptile = GUILayout.Toggle(settings.save_maptile, "是否保存 各类地形图像 （注意，很大，很慢）");
                        //settings.save_battleBack = GUILayout.Toggle(settings.save_battleBack, "是否保存 各类战斗背景图像 （注意，很大，很慢）");
                        StartSaveSprites();
                        GUILayout.Label($"剩余<color=#F28234>{spriteCounter}</color>个sprite等待导出");
                    }
                    GUILayout.EndVertical();
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndVertical();
        }

        private static void OnSaveGUI(UnityModManager.ModEntry modEntry)
        {
            settings.Save(modEntry);
        }

        private static void StartSaveSprites()
        {
            // 游戏载入成功后再允许导出，否则会造成游戏UI NullReferenceException
            if (!DateFile.instance.openGame)
            {
                GUILayout.Label("请先进入游戏主菜单即可保存......");
            }
            else
            {
                if (spriteCounter == 0)
                {
                    if (GUILayout.Button("点击导出贴图(Sprites)", GUILayout.Width(150f)))
                    {
                        try
                        {
                            // 删除备份目录中的文件并导出贴图
                            if (Directory.Exists(backupimgdir))
                            {
                                Directory.Delete(backupimgdir, true);
                            }
                            Directory.CreateDirectory(backupimgdir);
                            SpriteLoadHelper.GetInstance().DumpCommonSprite();
                            SpriteLoadHelper.GetInstance().DumpSpecialSprite();
                            SpriteLoadHelper.ClearInstance();
                        }
                        catch (Exception e)
                        {
                            Logger.Log($"保存Sprite:\n{e.ToString()}");
                        }
                    }
                }
                else
                {
                    GUILayout.Label("正在导出...", GUILayout.Width(150f));
                }
            }
        }

        internal static readonly Dictionary<int, string> textcolor = new Dictionary<int, string>
        {
            { 10000,"<color=#323232FF>"},
            { 10001,"<color=#4B4B4BFF>"},
            { 10002,"<color=#B97D4BFF>"},
            { 10003,"<color=#9B8773FF>"},
            { 10004,"<color=#AF3737FF>"},
            { 10005,"<color=#FFE100FF>"},
            { 10006,"<color=#FF44A7FF>"},
            { 20001,"<color=#E1CDAAFF>"},
            { 20002,"<color=#8E8E8EFF>"}, //九品灰
            { 20003,"<color=#FBFBFBFF>"}, //八品白
            { 20004,"<color=#6DB75FFF>"}, //七品绿
            { 20005,"<color=#8FBAE7FF>"}, //六品青
            { 20006,"<color=#63CED0FF>"}, //五品蓝
            { 20007,"<color=#AE5AC8FF>"}, //四品紫
            { 20008,"<color=#E3C66DFF>"}, //三品金
            { 20009,"<color=#F28234FF>"}, //二品橙
            { 20010,"<color=#E4504DFF>"}, //一品红
            { 20011,"<color=#EDA723FF>"},
        };

        internal static readonly Dictionary<string, string> date_instance_dict = new Dictionary<string, string>
        {
            {
                "ability_date",
                "abilityDate"
            }, {
                "actorattr_date",
                "actorAttrDate"
            }, {
                "actorfeature_date",
                "actorFeaturesDate"
            }, {
                "actormassage_date",
                "actorMassageDate"
            }, {
                "actorname_date",
                "actorNameDate"
            }, {
                "actorsurname_date",
                "actorSurnameDate"
            }, {
                "age_date",
                "ageDate"
            }, {
                "aishoping_date",
                "aiShopingDate"
            }, {
                "allworldmap_date",
                "allWorldDate"
            }, {
                "attacktyp_date",
                "attackTypDate"
            }, {
                "basemission_date",
                "baseMissionDate"
            }, {
                "baseskill_date",
                "baseSkillDate"
            }, {
                "basetips_date",
                "baseTipsDate"
            }, {
                "battlemap_date",
                "battleMapDate"
            }, {
                "battlerated_date",
                "battleRatedDate"
            }, {
                "battlestate_date",
                "battleStateDate"
            }, {
                "battletyp_date",
                "battleTypDate"
            }, {
                "body_date",
                "bodyInjuryDate"
            }, {
                "buffattr_date",
                "buffAttrDate"
            }, {
                "changeequip_date",
                "changeEquipDate"
            }, {
                "cricketbattle_date",
                "cricketBattleDate"
            }, {
                "cricket_date",
                "cricketDate"
            }, {
                "cricketplace_date",
                "cricketPlaceDate"
            }, {
                "enemyrand_date",
                "enemyRandDate"
            }, {
                "enemyteam_date",
                "enemyTeamDate"
            }, {
                "event_date",
                "eventDate"
            }, {
                "gamelevel_date",
                "gameLevelDate"
            }, {
                "gangequip_date",
                "gangEquipDate"
            }, {
                "ganggroup_date",
                "presetGangGroupDate"
            }, {
                "ganggroupvalue_date",
                "presetGangGroupDateValue"
            }, {
                "generation_date",
                "generationDate"
            }, {
                "gongfa_date",
                "gongFaDate"
            }, {
                "gongfafpower_date",
                "gongFaFPowerDate"
            }, {
                "gongfaotherfpower_date",
                "gongFaFPowerDate"
            }, // otherFPower 合并入 gongFaFPowerDate
            {
                "goodness_date",
                "goodnessDate"
            }, {
                "homeplace_date",
                "basehomePlaceDate"
            }, {
                "homeshopevent_date",
                "homeShopEventDate"
            }, {
                "homeshopeventtyp_date",
                "homeShopEventTypDate"
            }, {
                "hometyp_date",
                "homeTypDate"
            }, {
                "identity_date",
                "identityDate"
            }, {
                "injury_date",
                "injuryDate"
            }, {
                "item_date",
                "presetitemDate"
            }, {
                "itempower_date",
                "itemPowerDate"
            }, {
                "juniorxiangshu_data",
                "juniorXiangshuData"
            }, {
                "legendbook_data",
                "legendBookData"
            }, {
                "legendbookeffect_data",
                "legendBookEffectData"
            }, {
                "loadingimage_date",
                "loadingImageDate"
            }, {
                "makeitem_date",
                "makeItemDate"
            }, {
                "massage_date",
                "massageDate"
            }, {
                "moodtyp_date",
                "moodTypDate"
            }, {
                "palceworld_date",
                "placeWorldDate"
            }, {
                "partworldmap_date",
                "partWorldMapDate"
            }, {
                "poison_date",
                "poisonDate"
            }, {
                "presetactor_date",
                "presetActorDate"
            }, {
                "presetgang_date",
                "presetGangDate"
            }, {
                "qivaluestate_date",
                "qiValueStateDate"
            }, {
                "readbook_date",
                "readBookDate"
            }, {
                "resource_date",
                "resourceDate"
            }, {
                "scorebooty_date",
                "scoreBootyDate"
            }, {
                "scorevalue_date",
                "scoreValueDate"
            }, {
                "skill_date",
                "skillDate"
            }, {
                "solarterms_date",
                "solarTermsDate"
            }, {
                "storybuff_date",
                "storyBuffDate"
            }, {
                "story_date",
                "baseStoryDate"
            }, {
                "storyevent_date",
                "storyEventDate"
            }, {
                "storyshop_date",
                "storyShopDate"
            }, {
                "storyterrain_date",
                "storyTerrain"
            }, {
                "studydisk_date",
                "studyDiskDate"
            }, {
                "taichidisc_data",
                "taichiDiscData"
            }, {
                "talk_date",
                "talkDate"
            }, {
                "teaching_date",
                "teachingDate"
            }, {
                "timeworkbooty_date",
                "timeWorkBootyDate"
            }, {
                "tipsmassage_date",
                "tipsMassageDate"
            }, {
                "trunevent_date",
                "trunEventDate"
            }, {
                "villagename_date",
                "villageNameDate"
            },
            {
                "fame_date",
                "actorFameDate"
            }
        };

        internal static readonly Dictionary<string, string> sprite_instance_dict = new Dictionary<string, string>
        {
            {"TrunEventImage", "trunEventImage"},
            {"HomeMap/HomeBuildingIcon", "buildingSprites"},
            {"HomeMap/ReadBookIcon", "readStateIcon"},
            {"HomeMap/StudyStateImage", "studyStateImage"},
            {"HomeMap/StudyBookPage", "bookPageIcon"},
            {"StoryMap/StoryPlaceIcon", "storyPlaceIcon"},
            {"ItemIcon/ItemIcon", "itemSprites"},
            {"ItemIcon/ItemIconBack", "itemBackSprites"},
            {"GongFaImage/GongFaIcon", "gongFaSprites"},
            {"GongFaImage/GongFaCostIcon", "gongFaCostSprites"},
            {"GongFaImage/BigGongFaImage", "bigGongFaImage"},
            {"GangPowerIcon", "gangPowerIcon"},
            {"GoodnessIcon", "goodnessIcon"},
            {"HomeMap/HomeMapSprites", "homeMapSprites"},
            {"HomeMap/HomeMapBack", "homeMapBack"},
            {"StoryMap/StoryTerrain", "storyMapTerrain"},
            {"StoryMap/StoryMapBase", "storyMapBase"},
            {"StoryMap/StoryMapArrow", "storyMapArrow"},
            {"StoryMap/StoryEvent", "eventSprites"},
            {"NewGame/CityIcon", "mapPlaceIcon"},
            {"SkillImage/AllSkillIcon", "baseSkillIcon"},
            {"SkillImage/BigSkillImage", "bigSkillImage"},
            {"SkillImage/SkillImage", "baseSkillIcon"},
            {"HomeMap/HomeMapTypIcon", "homeTypIcon"},
            {"Cricket/CricketPlaceImage", "cricketPlaceImage"},
            {"Cricket/CricketBox", "cricketBox"},
            {"AttIcons", "attSprites"},
            {"InjuryIcons", "injuryIcon"},
            {"FeatureStarIcon", "featureStarIcon"},
            {"BattleTypText", "battleTypSprite"},
            {"BattleEndTyp", "battleEndTypImage"},
            {"BattleTeamActionIcon", "battleTeamActionIcon"},
            {"BattleFirstText", "battleFristSprite"},
            {"BattleUseImage", "battleUseImage"},
            {"BattlerDangerIcon", "battlerDangerIcon"},
            {"MakeResourceIcon", "makeResourceIcon"},
            {"PartIcon", "partIcon"},
            {"WorldMapPLayerIcon", "worldMapPlayerIcon"},
            {"PoisonSprites", "poisonSprites"},
            {"TimePaseSprite", "timePaseSprite"},
            {"TimeWorkImage", "timeWorkImage"},
        };

        /*internal static readonly Dictionary<string, string> sprite_loadpath_dict =new Dictionary<string, string>
        {
            {
                ""
            }
        }*/

        internal static T GetFieldValue<T>(object obj, string fieldName)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }

            var field = obj.GetType().GetField(fieldName, BindingFlags.Public |
                                                          BindingFlags.NonPublic |
                                                          BindingFlags.Instance);

            if (field == null)
            {
                throw new ArgumentException("fieldName", "No such field was found.");
            }

            if (!typeof(T).IsAssignableFrom(field.FieldType))
            {
                throw new InvalidOperationException("Field type and requested type are not compatible.");
            }

            return (T)field.GetValue(obj);
        }

        /// <summary>
        /// 获取数据文件对应的游戏数据字典
        /// </summary>
        /// <param name="cate"></param>
        /// <returns></returns>
        internal static Dictionary<int, Dictionary<int, string>> GetCSVDictRef(string cate)
        {
            if (cate == "actorface_date")
            {
                return GetSprites.instance.actorFaceDate;
            }
            if (date_instance_dict.TryGetValue(cate, out var dictName))
            {
                return GetFieldValue<Dictionary<int, Dictionary<int, string>>>(DateFile.instance, dictName);
            }
            return null;
        }
    }
}
