using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OfficeOpenXml;
using Thrift.Protocol;
using Thrift.Transport.Client;
using System.Threading;

namespace ThriftPipelineTools
{
    /// <summary>
    /// 快速生成 Bytes 工具（简化版）
    /// 只生成 AllConfigs.bytes，不生成 C# 和 DR
    /// 适用于表结构未变化，只需要更新数据的场景
    /// </summary>
    public class ThriftBytesGeneratorEditor : EditorWindow
    {
        // ========== 版本信息 ==========
        private const string VERSION = "v1.0.0 (Bytes Only)";
        
        // ========== 配置Key（使用EditorPrefs） ==========
        private const string PREF_KEY_DOCS_PATH = "ThriftPipeline_DocsPath";
        
        // ========== 路径配置 ==========
        private string docsProjectPath = "";    // Docs 项目路径
        
        // ========== UI 状态 ==========
        private Vector2 scrollPosition;
        private Vector2 logScrollPosition;
        private StringBuilder logBuilder = new StringBuilder();
        private bool isExecuting = false;
        
        // ========== 进度控制 ==========
        private float progress = 0f;
        private string currentStep = "";
        
        [MenuItem("蹊径/Thrift/快速生成 Bytes（简化版）")]
        public static void ShowWindow()
        {
            var window = GetWindow<ThriftBytesGeneratorEditor>("快速生成 Bytes");
            window.minSize = new Vector2(800, 600);
            window.Show();
        }
        
        private void OnEnable()
        {
            LoadConfig();
        }
        
        private void OnGUI()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField($"快速生成 Bytes 工具 - {VERSION}", EditorStyles.boldLabel);
            
            EditorGUILayout.HelpBox(
                "此工具只生成 AllConfigs.bytes 文件，不生成 C# 和 DR\n" +
                "适用于：表结构未变化，只需要更新配置数据的场景\n" +
                "⚡ 执行速度更快，跳过编译和代码生成步骤", 
                MessageType.Info
            );
            
            EditorGUILayout.Space(10);
            
            DrawPathConfiguration();
            
            EditorGUILayout.Space(10);
            
            DrawExecutionSection();
            
            EditorGUILayout.Space(10);
            
            DrawLogSection();
            
            EditorGUILayout.EndScrollView();
        }
        
        /// <summary>
        /// 绘制路径配置区域
        /// </summary>
        private void DrawPathConfiguration()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("路径配置", EditorStyles.boldLabel);
            
            EditorGUILayout.HelpBox(
                "只需配置 Docs 项目路径（包含 Excel 配置和 cfg_txt.json）",
                MessageType.None
            );
            
            // Docs 项目路径
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Docs 项目路径:", GUILayout.Width(120));
            docsProjectPath = EditorGUILayout.TextField(docsProjectPath);
            if (GUILayout.Button("选择", GUILayout.Width(60)))
            {
                string selected = EditorUtility.OpenFolderPanel("选择 Docs 项目路径", docsProjectPath, "");
                if (!string.IsNullOrEmpty(selected))
                {
                    docsProjectPath = selected;
                    SaveConfig();
                }
            }
            EditorGUILayout.EndHorizontal();
            
            // 显示派生路径预览
            if (!string.IsNullOrEmpty(docsProjectPath))
            {
                EditorGUILayout.Space(5);
                EditorGUILayout.LabelField("派生路径预览:", EditorStyles.miniLabel);
                
                var paths = GetDerivedPaths();
                EditorGUILayout.LabelField($"  cfg_txt.json: {paths["cfg_json"]}", EditorStyles.miniLabel);
                EditorGUILayout.LabelField($"  Config 目录: {paths["config_dir"]}", EditorStyles.miniLabel);
                EditorGUILayout.LabelField($"  输出到 Unity: {paths["unity_bytes_dir"]}", EditorStyles.miniLabel);
            }
            
            EditorGUILayout.EndVertical();
        }
        
        /// <summary>
        /// 绘制执行区域
        /// </summary>
        private void DrawExecutionSection()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("执行控制", EditorStyles.boldLabel);
            
            GUI.enabled = !isExecuting && ValidatePaths();
            
            if (GUILayout.Button("⚡ 快速生成 AllConfigs.bytes", GUILayout.Height(40)))
            {
                GenerateBytes();
            }
            
            GUI.enabled = true;
            
            if (isExecuting)
            {
                EditorGUILayout.Space(5);
                EditorGUILayout.LabelField($"当前步骤: {currentStep}");
                EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(GUILayout.Height(20)), progress, "执行中...");
            }
            
            EditorGUILayout.EndVertical();
        }
        
        /// <summary>
        /// 绘制日志区域
        /// </summary>
        private void DrawLogSection()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("执行日志", EditorStyles.boldLabel);
            
            logScrollPosition = EditorGUILayout.BeginScrollView(
                logScrollPosition,
                GUILayout.Height(300)
            );
            
            EditorGUILayout.TextArea(logBuilder.ToString(), GUILayout.ExpandHeight(true));
            
            EditorGUILayout.EndScrollView();
            
            if (GUILayout.Button("清空日志"))
            {
                logBuilder.Clear();
            }
            
            EditorGUILayout.EndVertical();
        }
        
        /// <summary>
        /// 加载配置（使用 EditorPrefs，本地保存，不会被git提交）
        /// </summary>
        private void LoadConfig()
        {
            try
            {
                docsProjectPath = EditorPrefs.GetString(PREF_KEY_DOCS_PATH, "");
            }
            catch (Exception ex)
            {
                Debug.LogError($"加载配置失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 保存配置（使用 EditorPrefs，本地保存，不会被git提交）
        /// </summary>
        private void SaveConfig()
        {
            try
            {
                EditorPrefs.SetString(PREF_KEY_DOCS_PATH, docsProjectPath);
            }
            catch (Exception ex)
            {
                Debug.LogError($"保存配置失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 获取所有派生路径
        /// </summary>
        private Dictionary<string, string> GetDerivedPaths()
        {
            var paths = new Dictionary<string, string>();
            
            // Docs 相关路径
            if (!string.IsNullOrEmpty(docsProjectPath))
            {
                paths["cfg_json"] = Path.Combine(docsProjectPath, "tool", "cfg", "cfg_txt.json");
                paths["config_dir"] = Path.Combine(docsProjectPath, "config");
            }
            
            // Unity 项目相关路径（当前项目）
            string assetsPath = Application.dataPath;
            paths["unity_bytes_dir"] = Path.Combine(assetsPath, "Design_SubModule", "ConfigData");
            
            return paths;
        }
        
        /// <summary>
        /// 验证路径
        /// </summary>
        private bool ValidatePaths()
        {
            if (string.IsNullOrEmpty(docsProjectPath))
                return false;
            
            var paths = GetDerivedPaths();
            
            if (!File.Exists(paths["cfg_json"]))
                return false;
            
            if (!Directory.Exists(paths["config_dir"]))
                return false;
            
            return true;
        }
        
        /// <summary>
        /// 日志输出
        /// </summary>
        private void Log(string message)
        {
            logBuilder.AppendLine(message);
            Repaint();
        }
        
        /// <summary>
        /// 生成 Bytes 文件
        /// </summary>
        private async void GenerateBytes()
        {
            isExecuting = true;
            logBuilder.Clear();
            progress = 0f;
            DateTime startTime = DateTime.Now;
            
            Log("================================================================================");
            Log($"开始生成 AllConfigs.bytes ({VERSION})");
            Log("================================================================================");
            Log("");
            
            try
            {
                var paths = GetDerivedPaths();
                
                currentStep = "读取配置并生成 bytes";
                progress = 0.3f;
                Repaint();
                
                if (!await GenerateBytesFile(paths))
                {
                    Log("[FAIL] 生成失败");
                    EditorUtility.DisplayDialog("失败", "生成 AllConfigs.bytes 失败，请查看日志", "确定");
                    return;
                }
                
                progress = 1f;
                currentStep = "完成";
                Repaint();
                
                DateTime endTime = DateTime.Now;
                TimeSpan duration = endTime - startTime;
                
                Log("");
                Log("================================================================================");
                Log($"✅ 生成完成！");
                Log($"   耗时: {duration.TotalSeconds:F2} 秒");
                Log($"   输出: {paths["unity_bytes_dir"]}/AllConfigs.bytes");
                Log("================================================================================");
                
                EditorUtility.DisplayDialog("成功", $"AllConfigs.bytes 生成完成！\n耗时: {duration.TotalSeconds:F2} 秒", "确定");
            }
            catch (Exception ex)
            {
                Log($"\n[FAIL] 执行失败: {ex.Message}");
                Log(ex.StackTrace);
                EditorUtility.DisplayDialog("错误", $"执行失败:\n{ex.Message}", "确定");
            }
            finally
            {
                isExecuting = false;
                AssetDatabase.Refresh();
                Repaint();
            }
        }
        
        /// <summary>
        /// 生成 Bytes 文件
        /// </summary>
        private async Task<bool> GenerateBytesFile(Dictionary<string, string> paths)
        {
            Log("【生成 AllConfigs.bytes】");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string cfgJsonPath = paths["cfg_json"];
                string configDir = paths["config_dir"];
                string bytesOutputDir = paths["unity_bytes_dir"];
                
                // 创建输出目录
                if (!Directory.Exists(bytesOutputDir))
                    Directory.CreateDirectory(bytesOutputDir);
                
                // 加载程序集
                Log("  [1/3] 加载程序集");
                System.Reflection.Assembly assembly = null;
                foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
                {
                    if (asm.GetType("Byway.Thrift.Data.AllConfigs") != null)
                    {
                        assembly = asm;
                        break;
                    }
                }
                
                if (assembly == null)
                {
                    Log("[FAIL] 找不到 Byway.Thrift.Data.AllConfigs 程序集");
                    Log("       请确保已经执行过完整流程，生成了 C# 类");
                    return false;
                }
                
                Log("    [OK] 程序集加载成功");
                
                // 读取配置
                Log("  [2/3] 读取配置并填充数据");
                string cfgText = File.ReadAllText(cfgJsonPath);
                var cfg = JsonConvert.DeserializeObject<JObject>(cfgText);
                var fileList = cfg["file_list"] as JArray;
                
                // 创建AllConfigs实例
                var allConfigsType = assembly.GetType("Byway.Thrift.Data.AllConfigs");
                object allConfigsInstance = Activator.CreateInstance(allConfigsType);
                
                int successCount = 0;
                int processedCount = 0;
                
                // 填充每个配置
                foreach (JObject configItem in fileList)
                {
                    string inFile = configItem["in_file"]?.ToString();
                    string outFile = configItem["out_file"]?.ToString();
                    string sheetName = configItem["sheet_name"]?.ToString();
                    var columnTypes = configItem["coloum_type"] as JArray;
                    
                    if (string.IsNullOrEmpty(inFile) || string.IsNullOrEmpty(outFile))
                        continue;
                    
                    string structName = outFile.Replace(".txt", "");
                    string excelPath = Path.Combine(configDir, inFile);
                    
                    if (!File.Exists(excelPath))
                    {
                        Log($"  [{++processedCount}] [SKIP] {structName} - Excel文件不存在");
                        continue;
                    }
                    
                    Log($"  [{++processedCount}] 处理: {structName}");
                    
                    if (FillThriftObject(allConfigsInstance, allConfigsType, structName, 
                        excelPath, sheetName, columnTypes, assembly))
                    {
                        successCount++;
                    }
                }
                
                // 序列化为bytes
                Log($"\n  [3/3] 序列化 AllConfigs.bytes (已设置 {successCount} 个配置)");
                
                // 检查有多少配置实际被设置
                int setCount = 0;
                var issetField = allConfigsType.GetField("__isset", 
                    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                if (issetField != null)
                {
                    var issetObj = issetField.GetValue(allConfigsInstance);
                    var issetType = issetObj.GetType();
                    foreach (var prop in allConfigsType.GetProperties())
                    {
                        if (prop.Name != "Isset" && prop.PropertyType.Namespace == "Byway.Thrift.Data")
                        {
                            var issetProp = issetType.GetProperty(prop.Name);
                            if (issetProp != null && (bool)issetProp.GetValue(issetObj))
                                setCount++;
                        }
                    }
                }
                Log($"    __isset 标志统计: {setCount} 个配置被标记为已设置");
                
                using (var memoryStream = new MemoryStream())
                {
                    using (var transport = new TStreamTransport(memoryStream, memoryStream, new Thrift.TConfiguration()))
                    {
                        using (var protocol = new TBinaryProtocol(transport))
                        {
                            var writeMethod = allConfigsType.GetMethod("WriteAsync");
                            if (writeMethod != null)
                            {
                                var task = (Task)writeMethod.Invoke(allConfigsInstance, 
                                    new object[] { protocol, CancellationToken.None });
                                await task;
                                
                                byte[] bytes = memoryStream.ToArray();
                                
                                string allConfigsBytesPath = Path.Combine(bytesOutputDir, "AllConfigs.bytes");
                                File.WriteAllBytes(allConfigsBytesPath, bytes);
                                
                                Log($"    [OK] 生成成功 ({bytes.Length} bytes / {bytes.Length / 1024.0:F2} KB)");
                                
                                if (bytes.Length < 1000)
                                {
                                    Log($"    [WARNING] 文件太小 ({bytes.Length} bytes)，可能大部分配置未序列化!");
                                }
                            }
                        }
                    }
                }
                
                Log($"\n生成完成: 成功 {successCount} 个配置");
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 生成失败: {ex.Message}");
                Log(ex.StackTrace);
                return false;
            }
        }
        
        /// <summary>
        /// 填充Thrift对象数据
        /// </summary>
        private bool FillThriftObject(object allConfigsInstance, Type allConfigsType, string structName,
            string excelPath, string sheetName, JArray columnTypes, System.Reflection.Assembly assembly)
        {
            try
            {
                var configType = assembly.GetType($"Byway.Thrift.Data.{structName}");
                var itemType = assembly.GetType($"Byway.Thrift.Data.{structName}Item");
                
                if (configType == null || itemType == null)
                {
                    Log($"    [ERROR] 找不到类型: {structName} 或 {structName}Item");
                    return false;
                }
                
                object configInstance = Activator.CreateInstance(configType);
                var dictType = typeof(Dictionary<,>).MakeGenericType(typeof(int), itemType);
                var dictInstance = Activator.CreateInstance(dictType);
                
                // 读取Excel
                FileInfo fileInfo = new FileInfo(excelPath);
                using (ExcelPackage package = new ExcelPackage(fileInfo))
                {
                    ExcelWorksheet worksheet = null;
                    if (!string.IsNullOrEmpty(sheetName) && package.Workbook.Worksheets[sheetName] != null)
                        worksheet = package.Workbook.Worksheets[sheetName];
                    else
                        worksheet = package.Workbook.Worksheets[0];
                    
                    if (worksheet == null || worksheet.Dimension == null)
                    {
                        Log($"    [ERROR] 工作表为空");
                        return false;
                    }
                    
                    int maxRows = worksheet.Dimension.End.Row;
                    int maxCols = worksheet.Dimension.End.Column;
                    
                    // 读取表头（第1行）
                    List<string> headers = new List<string>();
                    List<int> validColumns = new List<int>();
                    int maxColumns = columnTypes?.Count ?? maxCols;
                    
                    for (int col = 1; col <= maxCols && headers.Count < maxColumns; col++)
                    {
                        string header = worksheet.Cells[1, col].Value?.ToString() ?? "";
                        if (!string.IsNullOrWhiteSpace(header))
                        {
                            headers.Add(header);
                            validColumns.Add(col);
                        }
                    }
                    
                    // 读取数据（从第3行开始）
                    int filledItemCount = 0;
                    for (int row = 3; row <= maxRows; row++)
                    {
                        bool isEmptyRow = true;
                        for (int i = 0; i < validColumns.Count; i++)
                        {
                            if (worksheet.Cells[row, validColumns[i]].Value != null)
                            {
                                isEmptyRow = false;
                                break;
                            }
                        }
                        
                        if (isEmptyRow)
                            continue;
                        
                        object itemInstance = Activator.CreateInstance(itemType);
                        int? idValue = null;
                        
                        for (int i = 0; i < headers.Count; i++)
                        {
                            string originalHeader = headers[i];
                            string fieldName = SanitizeFieldName(originalHeader);
                            int colIndex = validColumns[i];
                            var cell = worksheet.Cells[row, colIndex];
                            object cellValue = cell.Value;
                            
                            var property = itemType.GetProperty(fieldName);
                            if (property != null)
                            {
                                try
                                {
                                    object convertedValue;
                                    
                                    if (cellValue == null)
                                    {
                                        if (property.PropertyType == typeof(string))
                                        {
                                            convertedValue = "";
                                        }
                                        else if (property.PropertyType.IsValueType)
                                        {
                                            convertedValue = Activator.CreateInstance(property.PropertyType);
                                        }
                                        else
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        convertedValue = ConvertCellValue(cellValue, property.PropertyType);
                                    }
                                    
                                    property.SetValue(itemInstance, convertedValue);
                                    
                                    if (fieldName.ToLower() == "id" && convertedValue is int)
                                        idValue = (int)convertedValue;
                                }
                                catch (Exception ex)
                                {
                                    Log($"      [WARN] 行{row} 字段{fieldName}转换失败: {ex.Message}");
                                }
                            }
                        }
                        
                        if (idValue.HasValue)
                        {
                            var addMethod = dictType.GetMethod("Add");
                            addMethod.Invoke(dictInstance, new object[] { idValue.Value, itemInstance });
                            filledItemCount++;
                        }
                    }
                    
                    Log($"    读取了 {filledItemCount} 条数据");
                }
                
                // 设置字典属性
                string dictPropertyName = char.ToUpper(structName[0]) + structName.Substring(1).ToLower() + "s";
                var dictProperty = configType.GetProperty(dictPropertyName);
                if (dictProperty != null)
                {
                    dictProperty.SetValue(configInstance, dictInstance);
                }
                else
                {
                    Log($"    [ERROR] 未找到字典属性: {dictPropertyName}");
                    return false;
                }
                
                // 设置到AllConfigs
                var allConfigProperty = allConfigsType.GetProperty(structName);
                if (allConfigProperty != null)
                {
                    allConfigProperty.SetValue(allConfigsInstance, configInstance);
                    
                    var verifyValue = allConfigProperty.GetValue(allConfigsInstance);
                    if (verifyValue == null)
                    {
                        Log($"    [ERROR] 设置到AllConfigs后为null!");
                        return false;
                    }
                    
                    Log($"    [OK] 成功");
                }
                else
                {
                    Log($"    [ERROR] AllConfigs中未找到属性: {structName}");
                    return false;
                }
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"    [ERROR] {structName}: {ex.Message}");
                return false;
            }
        }
        
        /// <summary>
        /// 清理并转换字段名为PascalCase
        /// </summary>
        private string SanitizeFieldName(string fieldName)
        {
            if (string.IsNullOrWhiteSpace(fieldName))
                return "Field_unknown";
            
            StringBuilder sb = new StringBuilder();
            foreach (char c in fieldName)
            {
                if (char.IsLetterOrDigit(c) || c == '_')
                    sb.Append(c);
                else if (c == ' ' || c == '-')
                    sb.Append('_');
            }
            
            string cleaned = sb.ToString();
            if (string.IsNullOrEmpty(cleaned))
                return "Field_unknown";
            
            if (cleaned.Length > 0)
            {
                return char.ToUpper(cleaned[0]) + cleaned.Substring(1);
            }
            
            return cleaned;
        }
        
        /// <summary>
        /// 转换单元格值
        /// </summary>
        private object ConvertCellValue(object cellValue, Type targetType)
        {
            try
            {
                if (targetType == typeof(int))
                {
                    if (cellValue is double d)
                        return (int)d;
                    return Convert.ToInt32(cellValue);
                }
                else if (targetType == typeof(long))
                {
                    if (cellValue is double d)
                        return (long)d;
                    return Convert.ToInt64(cellValue);
                }
                else if (targetType == typeof(double))
                {
                    return Convert.ToDouble(cellValue);
                }
                else if (targetType == typeof(bool))
                {
                    return Convert.ToBoolean(cellValue);
                }
                else if (targetType == typeof(string))
                {
                    return cellValue.ToString();
                }
                
                return cellValue;
            }
            catch
            {
                if (targetType == typeof(int)) return 0;
                if (targetType == typeof(long)) return 0L;
                if (targetType == typeof(double)) return 0.0;
                if (targetType == typeof(bool)) return false;
                if (targetType == typeof(string)) return "";
                return null;
            }
        }
    }
}
