using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using ArtResource;
using DesignTools.Common;
using OfficeOpenXml;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace DesignTools.Friends
{
    /// <summary>
    /// 好友馈赠宝箱奖励配置工具
    /// 读取 Docs/config/FriendTreasure.xlsx 的 Chest Sheet
    /// Items 的道具从 Item.xlsx 获取，支持查看图片、编辑数量与概率、增删行
    /// </summary>
    public class FriendTreasureChestEditor : BaseDesignToolEditor
    {
        private const string FRIEND_TREASURE_EXCEL_NAME = "FriendTreasure.xlsx";
        private const string FRIEND_TREASURE_SHEET_NAME = "Chest";
        private const string ITEM_EXCEL_NAME = "Item.xlsx";
        private const string ITEM_SHEET_NAME = "Item";
        private const string ART_SO_PATH = "Assets/Art_SubModule/Art_SO";

        private const int COL_ID = 1;
        private const int COL_ITEMS = 2;
        private const int COL_PROB = 3;
        private const int DATA_START_ROW = 3;
        private const int PROB_TOTAL = 1000;

        private readonly List<FriendTreasureChestRowData> chestRewardList = new List<FriendTreasureChestRowData>();
        private readonly Dictionary<int, FriendTreasureItemData> itemDict = new Dictionary<int, FriendTreasureItemData>();
        private readonly List<ArtTableSO> allArtTables = new List<ArtTableSO>();
        private readonly List<int> allItemTypes = new List<int>();

        [MenuItem("策划工具/好友/好友馈赠/宝箱奖励及概率")]
        public static void ShowWindow()
        {
            var window = GetWindow<FriendTreasureChestEditor>("宝箱奖励及概率");
            window.minSize = window.GetMinWindowSize();
            window.Show();
        }

        protected override string GetDocsPathPrefKey()
        {
            return "FriendTreasureChestEditor_DocsPath";
        }

        protected override string GetWindowTitle()
        {
            return "好友馈赠宝箱奖励及概率";
        }

        protected override Vector2 GetMinWindowSize()
        {
            return new Vector2(1200, 680);
        }

        protected override void LoadConfigData()
        {
            LoadAllArtTableSO();
            LoadItemData();
            LoadChestData();
        }

        protected override void DrawDataEditor()
        {
            DrawTipsAndToolbar();
            EditorGUILayout.Space(6);
            DrawChestRewardTable();
        }

        protected override void SaveDataToExcel()
        {
            SaveToExcel();
        }

        private void DrawTipsAndToolbar()
        {
            EditorGUILayout.BeginVertical("box");
            // EditorGUILayout.HelpBox("保存时只会写回 FriendTreasure.xlsx 的 Chest Sheet，不会改动其它 Sheet。", MessageType.Info);
            // EditorGUILayout.HelpBox("新增只能追加到最后；删除任意一行后，后续 Id 会自动前移并从 1 开始重新编号。", MessageType.Info);

            int totalProb = chestRewardList.Sum(x => x.Prob);
            float totalPercent = totalProb / 10f;
            MessageType messageType = totalProb == PROB_TOTAL ? MessageType.Info : MessageType.Error;
            EditorGUILayout.HelpBox($"当前总概率：{totalProb}/{PROB_TOTAL}（{totalPercent:F1}%）", messageType);

            EditorGUILayout.BeginHorizontal();
            GUI.backgroundColor = Color.green;
            if (GUILayout.Button("＋ 新增一行", GUILayout.Width(120), GUILayout.Height(28)))
            {
                AddNewRow();
            }
            GUI.backgroundColor = Color.white;

            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
        }

        private void DrawChestRewardTable()
        {
            EditorGUILayout.BeginVertical("box");

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Id", EditorStyles.boldLabel, GUILayout.Width(50));
            EditorGUILayout.LabelField("道具类型", EditorStyles.boldLabel, GUILayout.Width(130));
            EditorGUILayout.LabelField("奖励道具（可输ID / 搜索）", EditorStyles.boldLabel, GUILayout.Width(470));
            EditorGUILayout.LabelField("数量", EditorStyles.boldLabel, GUILayout.Width(80));
            EditorGUILayout.LabelField("概率", EditorStyles.boldLabel, GUILayout.Width(80));
            EditorGUILayout.LabelField("百分比", EditorStyles.boldLabel, GUILayout.Width(90));
            EditorGUILayout.LabelField("预览", EditorStyles.boldLabel, GUILayout.Width(70));
            EditorGUILayout.LabelField("操作", EditorStyles.boldLabel, GUILayout.Width(70));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(4);

            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            for (int i = 0; i < chestRewardList.Count; i++)
            {
                FriendTreasureChestRowData rowData = chestRewardList[i];
                DrawSingleRow(i, rowData);
                EditorGUILayout.Space(4);
            }

            EditorGUILayout.EndScrollView();
            EditorGUILayout.EndVertical();
        }

        private void DrawSingleRow(int index, FriendTreasureChestRowData rowData)
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.BeginHorizontal();

            EditorGUILayout.LabelField(rowData.Id.ToString(), GUILayout.Width(50));

            DrawItemSelector(rowData);

            rowData.Num = EditorGUILayout.IntField(rowData.Num, GUILayout.Width(80));
            rowData.Prob = EditorGUILayout.IntField(rowData.Prob, GUILayout.Width(80));
            EditorGUILayout.LabelField(GetPercentText(rowData.Prob), GUILayout.Width(90));

            DrawItemPreview(rowData.RewardItemId);

            GUI.backgroundColor = new Color(1f, 0.55f, 0.55f);
            if (GUILayout.Button("删除", GUILayout.Width(60), GUILayout.Height(22)))
            {
                RemoveRow(index);
                GUI.backgroundColor = Color.white;
                GUIUtility.ExitGUI();
            }
            GUI.backgroundColor = Color.white;

            EditorGUILayout.EndHorizontal();

            if (itemDict.TryGetValue(rowData.RewardItemId, out FriendTreasureItemData itemData))
            {
                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(54);
                EditorGUILayout.LabelField($"当前道具：{itemData.Name} ({itemData.Id})", EditorStyles.miniLabel);
                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.EndVertical();
        }

        private void DrawItemSelector(FriendTreasureChestRowData rowData)
        {
            EnsureInputItemId(rowData);

            int currentType = GetCurrentItemType(rowData.RewardItemId);
            if (currentType < 0 && allItemTypes.Count > 0)
            {
                currentType = allItemTypes[0];
            }

            int currentTypeIndex = Mathf.Max(0, allItemTypes.IndexOf(currentType));
            string[] typeOptions = allItemTypes.Select(GetItemTypeDisplayName).ToArray();

            if (typeOptions.Length == 0)
            {
                EditorGUILayout.LabelField("无可用类型", GUILayout.Width(130));
                EditorGUILayout.LabelField("无可用道具", GUILayout.Width(470));
                return;
            }

            int newTypeIndex = EditorGUILayout.Popup(currentTypeIndex, typeOptions, GUILayout.Width(130));
            int selectedType = allItemTypes[newTypeIndex];

            List<FriendTreasureItemData> itemsOfType = itemDict.Values
                .Where(x => x.IType == selectedType)
                .OrderBy(x => x.Id)
                .ToList();

            if (itemsOfType.Count == 0)
            {
                EditorGUILayout.LabelField("该类型无道具", GUILayout.Width(470));
                return;
            }

            EditorGUILayout.BeginVertical(GUILayout.Width(470));

            EditorGUILayout.BeginHorizontal();
            int newInputItemId = EditorGUILayout.IntField(rowData.InputItemId, GUILayout.Width(90));
            if (newInputItemId != rowData.InputItemId)
            {
                rowData.InputItemId = newInputItemId;
                if (itemDict.ContainsKey(newInputItemId))
                {
                    SetRowItem(rowData, newInputItemId);
                    currentType = GetCurrentItemType(rowData.RewardItemId);
                    selectedType = currentType;
                    itemsOfType = itemDict.Values
                        .Where(x => x.IType == selectedType)
                        .OrderBy(x => x.Id)
                        .ToList();
                }
            }

            GUI.backgroundColor = new Color(0.75f, 0.9f, 1f);
            if (GUILayout.Button("查找", GUILayout.Width(55), GUILayout.Height(20)))
            {
                EditorApplication.delayCall += () => OpenItemPickerWindow(rowData);
                GUI.backgroundColor = Color.white;
                GUIUtility.ExitGUI();
            }
            GUI.backgroundColor = Color.white;

            if (itemDict.TryGetValue(rowData.InputItemId, out FriendTreasureItemData inputItemData))
            {
                EditorGUILayout.LabelField($"{inputItemData.Name} ({inputItemData.Id})", EditorStyles.miniLabel, GUILayout.Width(300));
            }
            else
            {
                Color oldColor = GUI.color;
                GUI.color = new Color(1f, 0.35f, 0.35f);
                EditorGUILayout.LabelField("未找到该 ItemId", EditorStyles.miniLabel, GUILayout.Width(300));
                GUI.color = oldColor;
            }
            EditorGUILayout.EndHorizontal();

            int currentItemIndex = itemsOfType.FindIndex(x => x.Id == rowData.RewardItemId);
            if (currentItemIndex < 0)
            {
                currentItemIndex = 0;
                SetRowItem(rowData, itemsOfType[0].Id);
            }

            string[] itemOptions = itemsOfType
                .Select(x => $"{x.Name} ({x.Id})")
                .ToArray();

            int newItemIndex = EditorGUILayout.Popup(currentItemIndex, itemOptions, GUILayout.Width(460));
            SetRowItem(rowData, itemsOfType[newItemIndex].Id);

            EditorGUILayout.EndVertical();
        }

        private void EnsureInputItemId(FriendTreasureChestRowData rowData)
        {
            if (rowData.InputItemId <= 0)
            {
                rowData.InputItemId = rowData.RewardItemId;
            }
        }

        private void SetRowItem(FriendTreasureChestRowData rowData, int itemId)
        {
            rowData.RewardItemId = itemId;
            rowData.InputItemId = itemId;
        }

        private void OpenItemPickerWindow(FriendTreasureChestRowData rowData)
        {
            int currentType = GetCurrentItemType(rowData.RewardItemId);
            DesignToolItemPickerWindow.ShowWindow(
                itemDict.Values
                    .Select(x => new DesignToolItemPickerItem
                    {
                        Id = x.Id,
                        Name = x.Name,
                        IType = x.IType
                    })
                    .ToList(),
                allItemTypes,
                ITEM_TYPE_NAMES,
                currentType,
                rowData.RewardItemId,
                position,
                selectedItemId =>
                {
                    SetRowItem(rowData, selectedItemId);
                    Repaint();
                });
        }

        private void AddNewRow()
        {
            int defaultItemId = itemDict.Count > 0 ? itemDict.Values.OrderBy(x => x.Id).First().Id : 0;

            chestRewardList.Add(new FriendTreasureChestRowData
            {
                Id = chestRewardList.Count + 1,
                RewardItemId = defaultItemId,
                InputItemId = defaultItemId,
                Num = 1,
                Prob = 0
            });
        }

        private void RemoveRow(int index)
        {
            if (index < 0 || index >= chestRewardList.Count)
            {
                return;
            }

            chestRewardList.RemoveAt(index);
            ReassignIds();
        }

        private void ReassignIds()
        {
            for (int i = 0; i < chestRewardList.Count; i++)
            {
                chestRewardList[i].Id = i + 1;
            }
        }

        private void LoadAllArtTableSO()
        {
            allArtTables.Clear();

            string[] guids = AssetDatabase.FindAssets("t:ArtTableSO", new[] { ART_SO_PATH });
            foreach (string guid in guids)
            {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                ArtTableSO artTable = AssetDatabase.LoadAssetAtPath<ArtTableSO>(path);
                if (artTable != null)
                {
                    allArtTables.Add(artTable);
                }
            }

            Debug.Log($"加载了 {allArtTables.Count} 个 ArtTableSO 资源");
        }

        private void LoadItemData()
        {
            itemDict.Clear();
            allItemTypes.Clear();

            string itemExcelPath = GetDocsConfigFilePath(ITEM_EXCEL_NAME);
            if (!File.Exists(itemExcelPath))
            {
                throw new FileNotFoundException($"未找到 {ITEM_EXCEL_NAME}", itemExcelPath);
            }

            using (var package = new ExcelPackage(new FileInfo(itemExcelPath)))
            {
                var worksheet = package.Workbook.Worksheets[ITEM_SHEET_NAME];
                if (worksheet == null)
                {
                    throw new Exception($"{ITEM_EXCEL_NAME} 中未找到 Sheet: {ITEM_SHEET_NAME}");
                }

                int idCol = -1;
                int nameCol = -1;
                int iTypeCol = -1;
                int resCol = -1;
                int columnCount = worksheet.Dimension?.Columns ?? 0;

                for (int col = 1; col <= columnCount; col++)
                {
                    string header = worksheet.Cells[1, col].Text;
                    if (header == "Id") idCol = col;
                    else if (header == "Name") nameCol = col;
                    else if (header == "IType") iTypeCol = col;
                    else if (header == "Res") resCol = col;
                }

                if (idCol < 0 || nameCol < 0 || iTypeCol < 0)
                {
                    throw new Exception("Item.xlsx 表结构不正确，缺少 Id / Name / IType 列");
                }

                int rowCount = worksheet.Dimension?.Rows ?? 0;
                for (int row = DATA_START_ROW; row <= rowCount; row++)
                {
                    string idText = worksheet.Cells[row, idCol].Text.Trim();
                    if (string.IsNullOrEmpty(idText))
                    {
                        continue;
                    }

                    if (!int.TryParse(idText, out int id))
                    {
                        continue;
                    }

                    string name = worksheet.Cells[row, nameCol].Text.Trim();
                    string iTypeText = worksheet.Cells[row, iTypeCol].Text.Trim();
                    string res = resCol > 0 ? worksheet.Cells[row, resCol].Text.Trim() : string.Empty;

                    if (!int.TryParse(iTypeText, out int iType))
                    {
                        continue;
                    }

                    itemDict[id] = new FriendTreasureItemData
                    {
                        Id = id,
                        Name = name,
                        IType = iType,
                        Res = res
                    };
                }
            }

            foreach (int itemType in itemDict.Values.Select(x => x.IType).Distinct().OrderBy(x => x))
            {
                allItemTypes.Add(itemType);
            }

            Debug.Log($"加载了 {itemDict.Count} 个 Item 数据");
        }

        private void LoadChestData()
        {
            chestRewardList.Clear();

            string excelPath = GetDocsConfigFilePath(FRIEND_TREASURE_EXCEL_NAME);
            if (!File.Exists(excelPath))
            {
                throw new FileNotFoundException($"未找到 {FRIEND_TREASURE_EXCEL_NAME}", excelPath);
            }

            using (var package = new ExcelPackage(new FileInfo(excelPath)))
            {
                var worksheet = package.Workbook.Worksheets[FRIEND_TREASURE_SHEET_NAME];
                if (worksheet == null)
                {
                    throw new Exception($"未找到 Sheet: {FRIEND_TREASURE_SHEET_NAME}");
                }

                int rowCount = worksheet.Dimension?.Rows ?? 0;
                for (int row = DATA_START_ROW; row <= rowCount; row++)
                {
                    string idText = worksheet.Cells[row, COL_ID].Text.Trim();
                    if (string.IsNullOrEmpty(idText))
                    {
                        continue;
                    }

                    if (!int.TryParse(idText, out int id))
                    {
                        continue;
                    }

                    string itemsText = worksheet.Cells[row, COL_ITEMS].Text.Trim();
                    int prob = ParseInt(worksheet.Cells[row, COL_PROB].Text.Trim());

                    if (!TryParseItems(itemsText, out int itemId, out int num))
                    {
                        Debug.LogWarning($"{FRIEND_TREASURE_EXCEL_NAME}/{FRIEND_TREASURE_SHEET_NAME} 第 {row} 行 Items 格式异常，已使用默认值");
                        itemId = itemDict.Count > 0 ? itemDict.Keys.Min() : 0;
                        num = 1;
                    }

                    chestRewardList.Add(new FriendTreasureChestRowData
                    {
                        Id = id,
                        RewardItemId = itemId,
                        InputItemId = itemId,
                        Num = num,
                        Prob = prob,
                        RowIndex = row
                    });
                }
            }

            ReassignIds();
        }

        private void SaveToExcel()
        {
            ReassignIds();

            if (!ValidateBeforeSave(out string errorMessage))
            {
                EditorUtility.DisplayDialog("校验失败", errorMessage, "确定");
                return;
            }

            try
            {
                string excelPath = GetDocsConfigFilePath(FRIEND_TREASURE_EXCEL_NAME);
                using (var package = new ExcelPackage(new FileInfo(excelPath)))
                {
                    var worksheet = package.Workbook.Worksheets[FRIEND_TREASURE_SHEET_NAME];
                    if (worksheet == null)
                    {
                        EditorUtility.DisplayDialog("错误", $"未找到 Sheet: {FRIEND_TREASURE_SHEET_NAME}", "确定");
                        return;
                    }

                    int rowCount = worksheet.Dimension?.Rows ?? 0;

                    for (int i = 0; i < chestRewardList.Count; i++)
                    {
                        FriendTreasureChestRowData rowData = chestRewardList[i];
                        int row = DATA_START_ROW + i;

                        worksheet.Cells[row, COL_ID].Value = rowData.Id;
                        worksheet.Cells[row, COL_ITEMS].Value = BuildItemsJson(rowData.RewardItemId, rowData.Num);
                        worksheet.Cells[row, COL_PROB].Value = rowData.Prob;
                    }

                    for (int row = DATA_START_ROW + chestRewardList.Count; row <= rowCount; row++)
                    {
                        worksheet.Cells[row, COL_ID].Value = null;
                        worksheet.Cells[row, COL_ITEMS].Value = null;
                        worksheet.Cells[row, COL_PROB].Value = null;
                    }

                    package.Save();
                }

                EditorUtility.DisplayDialog("成功", "宝箱奖励及概率已保存到 Chest Sheet！", "确定");
                Debug.Log("宝箱奖励及概率已保存");
            }
            catch (Exception e)
            {
                EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定");
                Debug.LogError($"保存宝箱奖励及概率失败: {e}");
            }
        }

        private bool ValidateBeforeSave(out string errorMessage)
        {
            if (chestRewardList.Count == 0)
            {
                errorMessage = "至少需要保留一条宝箱奖励数据。";
                return false;
            }

            for (int i = 0; i < chestRewardList.Count; i++)
            {
                FriendTreasureChestRowData rowData = chestRewardList[i];
                if (!itemDict.ContainsKey(rowData.RewardItemId))
                {
                    errorMessage = $"第 {i + 1} 行选择的 ItemId 不存在于 Item.xlsx 中。";
                    return false;
                }

                if (rowData.Num < 1)
                {
                    errorMessage = $"第 {i + 1} 行的数量必须大于等于 1。";
                    return false;
                }

                if (rowData.Prob < 0)
                {
                    errorMessage = $"第 {i + 1} 行的概率不能小于 0。";
                    return false;
                }
            }

            int totalProb = chestRewardList.Sum(x => x.Prob);
            if (totalProb != PROB_TOTAL)
            {
                errorMessage = $"所有概率之和必须等于 {PROB_TOTAL}，当前为 {totalProb}。";
                return false;
            }

            errorMessage = string.Empty;
            return true;
        }

        private bool TryParseItems(string itemsText, out int itemId, out int num)
        {
            itemId = 0;
            num = 0;

            if (string.IsNullOrWhiteSpace(itemsText))
            {
                return false;
            }

            Match idMatch = Regex.Match(itemsText, @"""Id""\s*:\s*(\d+)");
            Match numMatch = Regex.Match(itemsText, @"""Num""\s*:\s*(-?\d+)");
            if (!idMatch.Success || !numMatch.Success)
            {
                return false;
            }

            return int.TryParse(idMatch.Groups[1].Value, out itemId) &&
                   int.TryParse(numMatch.Groups[1].Value, out num);
        }

        private string BuildItemsJson(int itemId, int num)
        {
            return $"[{{\"Id\":{itemId},\"Num\":{num}}}]";
        }

        private int ParseInt(string text)
        {
            return int.TryParse(text, out int value) ? value : 0;
        }

        private string GetPercentText(int prob)
        {
            return $"{prob / 10f:F1}%";
        }

        private int GetCurrentItemType(int itemId)
        {
            return itemDict.TryGetValue(itemId, out FriendTreasureItemData itemData) ? itemData.IType : -1;
        }

        private string GetItemTypeDisplayName(int iType)
        {
            return ITEM_TYPE_NAMES.TryGetValue(iType, out string typeName)
                ? $"{typeName} ({iType})"
                : $"类型 {iType}";
        }

        private void DrawItemPreview(int itemId)
        {
            if (!itemDict.TryGetValue(itemId, out FriendTreasureItemData itemData) || string.IsNullOrEmpty(itemData.Res))
            {
                EditorGUILayout.LabelField("无图", GUILayout.Width(70));
                return;
            }

            string[] parts = itemData.Res.Split(',');
            if (parts.Length != 2)
            {
                EditorGUILayout.LabelField("无图", GUILayout.Width(70));
                return;
            }

            string tableName = parts[0];
            string artItemName = parts[1];
            
            if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(artItemName))
            {
                EditorGUILayout.LabelField("无图", GUILayout.Width(70));
                return;
            }

            ArtTableSO artTable = allArtTables.FirstOrDefault(x => x.TableName == tableName);
            if (artTable == null)
            {
                EditorGUILayout.LabelField("无图", GUILayout.Width(70));
                return;
            }

            var artItem = artTable.Items.FirstOrDefault(x => x.Name == artItemName);
            if (artItem == null || artItem.Sprite == null)
            {
                EditorGUILayout.LabelField("无图", GUILayout.Width(70));
                return;
            }

            Rect rect = GUILayoutUtility.GetRect(50, 50, GUILayout.Width(50), GUILayout.Height(50));
            GUI.DrawTexture(rect, artItem.Sprite.texture, ScaleMode.ScaleToFit);
        }

        private static readonly Dictionary<int, string> ITEM_TYPE_NAMES = new Dictionary<int, string>
        {
            { 1, "能量" },
            { 2, "星星" },
            { 3, "钻石" },
            { 97, "Playroom宠物道具" },
            { 98, "卡牌" },
            { 99, "背包道具" },
            { 100, "棋子" },
            { 101, "卡包" },
            { 102, "限时事件" },
            { 103, "小猪存钱罐" },
            { 104, "万能卡" },
            { 105, "头像框" },
            { 106, "活动代币" },
            { 107, "竞赛游戏代币" },
            { 108, "Pet Playroom拜访道具" },
            { 109, "表情" },
            { 110, "头像" },
            { 111, "Playroom装饰" },
            { 112, "Playroom服装" },
            { 113, "Playroom装饰套装" },
            { 114, "Playroom服装套装" },
            { 115, "Playroom道具宝箱" },
            { 116, "活动通行证代币道具" }
        };
    }

    [Serializable]
    public class FriendTreasureChestRowData
    {
        public int Id;
        public int RewardItemId;
        public int InputItemId;
        public int Num;
        public int Prob;
        public int RowIndex;
    }

    [Serializable]
    public class FriendTreasureItemData
    {
        public int Id;
        public string Name;
        public int IType;
        public string Res;
    }
}
