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

namespace ThriftPipelineTools
{
    /// <summary>
    /// 导入 Docs 配置表工具
    /// 完全复刻 integrated_pipeline.py 的功能
    /// 从 Excel 到 Unity 的一站式处理
    /// </summary>
    public class ThriftIntegratedPipelineEditor : EditorWindow
    {
        // ========== 版本信息 ==========
        private const string VERSION = "v1.0.0 (C# Edition)";
        
        // ========== 路径配置 ==========
        private string docsProjectPath = "";    // Docs 项目路径
        private string thriftProjectPath = "";  // Thrift 项目路径
        
        // ========== UI 状态 ==========
        private Vector2 scrollPosition;
        private Vector2 logScrollPosition;
        private StringBuilder logBuilder = new StringBuilder();
        private bool isExecuting = false;
        
        // ========== 进度控制 ==========
        private float progress = 0f;
        private string currentStep = "";
        private int totalSteps = 7;
        private int completedSteps = 0;
        
        // ========== 报告数据 ==========
        private List<StepReport> reportSteps = new List<StepReport>();
        private DateTime startTime;
        private DateTime endTime;
        
        // ========== 配置Key（使用EditorPrefs） ==========
        private const string PREF_KEY_DOCS_PATH = "ThriftPipeline_DocsPath";
        private const string PREF_KEY_THRIFT_PATH = "ThriftPipeline_ThriftPath";
        
        // ========== 临时数据 ==========
        private List<string> configStructNames = new List<string>();
        
        [MenuItem("蹊径/Thrift/导入 Docs 配置表工具")]
        public static void ShowWindow()
        {
            var window = GetWindow<ThriftIntegratedPipelineEditor>("导入 Docs 配置表工具");
            window.minSize = new Vector2(1000, 800);
            window.Show();
        }
        
        private void OnEnable()
        {
            LoadConfig();
        }
        
        private void OnGUI()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField($"导入 Docs 配置表工具 - {VERSION}", EditorStyles.boldLabel);
            
            EditorGUILayout.HelpBox(
                "此工具完全复刻 integrated_pipeline.py 的功能\n" +
                "从 Excel 配置文件生成 Thrift 定义、编译为 C# 代码、生成二进制数据、创建 DataRow 类\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(
                "配置两个基础路径，其他路径将自动推导\n" +
                "- Docs 项目路径: 包含 Excel 配置和 cfg_txt.json\n" +
                "- Thrift 项目路径: 包含 thrift.exe 编译器和 thrift 文件目录",
                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();
            
            // Thrift 项目路径
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Thrift 项目路径:", GUILayout.Width(120));
            thriftProjectPath = EditorGUILayout.TextField(thriftProjectPath);
            if (GUILayout.Button("选择", GUILayout.Width(60)))
            {
                string selected = EditorUtility.OpenFolderPanel("选择 Thrift 项目路径", thriftProjectPath, "");
                if (!string.IsNullOrEmpty(selected))
                {
                    thriftProjectPath = selected;
                    SaveConfig();
                }
            }
            EditorGUILayout.EndHorizontal();
            
            // 显示派生路径预览
            if (!string.IsNullOrEmpty(docsProjectPath) && !string.IsNullOrEmpty(thriftProjectPath))
            {
                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($"  Thrift 编译器: {paths["compiler"]}", EditorStyles.miniLabel);
                EditorGUILayout.LabelField($"  输出到 Unity C#: {paths["unity_csharp_dir"]}", EditorStyles.miniLabel);
                EditorGUILayout.LabelField($"  输出到 Unity Bytes: {paths["unity_bytes_dir"]}", EditorStyles.miniLabel);
                EditorGUILayout.LabelField($"  输出到 Unity DR: {paths["dr_output_dir"]}", EditorStyles.miniLabel);
            }
            
            EditorGUILayout.EndVertical();
        }
        
        /// <summary>
        /// 绘制执行区域
        /// </summary>
        private void DrawExecutionSection()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField("执行控制", EditorStyles.boldLabel);
            
            GUI.enabled = !isExecuting && ValidatePaths();
            
            if (GUILayout.Button("🚀 开始执行完整流程", GUILayout.Height(40)))
            {
                ExecutePipeline();
            }
            
            GUI.enabled = true;
            
            if (isExecuting)
            {
                EditorGUILayout.Space(5);
                EditorGUILayout.LabelField($"当前步骤: {currentStep}");
                EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(GUILayout.Height(20)), progress, $"{completedSteps}/{totalSteps}");
            }
            
            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
            {
                // 从 EditorPrefs 读取路径（每台电脑独立保存）
                docsProjectPath = EditorPrefs.GetString(PREF_KEY_DOCS_PATH, "");
                thriftProjectPath = EditorPrefs.GetString(PREF_KEY_THRIFT_PATH, "");
            }
            catch (Exception ex)
            {
                Debug.LogError($"加载配置失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 保存配置（使用 EditorPrefs，本地保存，不会被git提交）
        /// </summary>
        private void SaveConfig()
        {
            try
            {
                // 保存到 EditorPrefs（每台电脑独立保存，不会被git追踪）
                EditorPrefs.SetString(PREF_KEY_DOCS_PATH, docsProjectPath);
                EditorPrefs.SetString(PREF_KEY_THRIFT_PATH, thriftProjectPath);
            }
            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");
            }
            
            // Thrift 项目相关路径（包含中间输出目录）
            if (!string.IsNullOrEmpty(thriftProjectPath))
            {
                paths["thrift_project_path"] = thriftProjectPath;  // 添加项目根路径供Python脚本使用
                paths["compiler"] = Path.Combine(thriftProjectPath, "compiler", "exe", "thrift.exe");
                paths["thrift_dir"] = Path.Combine(thriftProjectPath, "thrift-files", "meowment");
                paths["csharp_output_dir"] = Path.Combine(thriftProjectPath, "compiled_output", "csharp");
                paths["bytes_output_dir"] = Path.Combine(thriftProjectPath, "binary_output");
            }
            
            // Unity 项目相关路径（当前项目）
            string assetsPath = Application.dataPath;
            paths["unity_csharp_dir"] = Path.Combine(assetsPath, "Design_SubModule", "Scripts", "thrift", "gen-netstd");
            paths["unity_bytes_dir"] = Path.Combine(assetsPath, "Design_SubModule", "ConfigData");
            paths["dr_output_dir"] = Path.Combine(assetsPath, "Design_SubModule", "Scripts", "DR_Generated");
            
            return paths;
        }
        
        /// <summary>
        /// 验证路径
        /// </summary>
        private bool ValidatePaths()
        {
            if (string.IsNullOrEmpty(docsProjectPath) || string.IsNullOrEmpty(thriftProjectPath))
                return false;
            
            var paths = GetDerivedPaths();
            
            if (!File.Exists(paths["cfg_json"]))
                return false;
            
            if (!Directory.Exists(paths["config_dir"]))
                return false;
            
            if (!File.Exists(paths["compiler"]))
                return false;
            
            return true;
        }
        
        /// <summary>
        /// 日志输出
        /// </summary>
        private void Log(string message)
        {
            logBuilder.AppendLine(message);
            Repaint();
        }
        
        /// <summary>
        /// 添加步骤报告
        /// </summary>
        private void AddStepReport(string stepName, bool success, Dictionary<string, object> details = null)
        {
            reportSteps.Add(new StepReport
            {
                Name = stepName,
                Success = success,
                Time = DateTime.Now,
                Details = details ?? new Dictionary<string, object>()
            });
        }
        
        /// <summary>
        /// 更新进度
        /// </summary>
        private void UpdateProgress(int step, string stepName)
        {
            completedSteps = step;
            currentStep = stepName;
            progress = (float)completedSteps / totalSteps;
            Repaint();
        }
        
        /// <summary>
        /// 执行完整流程
        /// </summary>
        private async void ExecutePipeline()
        {
            isExecuting = true;
            logBuilder.Clear();
            reportSteps.Clear();
            completedSteps = 0;
            startTime = DateTime.Now;
            
            Log("================================================================================");
            Log($"开始执行完整流程 ({VERSION})");
            Log("================================================================================");
            Log("");
            
            try
            {
                var paths = GetDerivedPaths();
                
                // 步骤1: 生成 Thrift 文件
                UpdateProgress(0, "步骤1: 生成 Thrift 文件");
                if (!await Step1_GenerateThriftFiles(paths))
                {
                    Log("[FAIL] 步骤1失败，终止执行");
                    return;
                }
                
                // 步骤2: 编译 Thrift 到 C#
                UpdateProgress(1, "步骤2: 编译 Thrift 到 C#");
                if (!await Step2_CompileToCSharp(paths))
                {
                    Log("[FAIL] 步骤2失败，终止执行");
                    return;
                }
                
                // 步骤3: 生成 Bytes 文件
                UpdateProgress(2, "步骤3: 生成 Bytes 文件");
                if (!await Step3_GenerateBytes(paths))
                {
                    Log("[FAIL] 步骤3失败，终止执行");
                    return;
                }
                
                // 步骤4: 清理冲突文件
                UpdateProgress(3, "步骤4: 清理冲突文件");
                if (!Step4_CleanupExtensions(paths))
                {
                    Log("[FAIL] 步骤4失败，终止执行");
                    return;
                }
                
                // 步骤5: 复制 C# 到 Unity
                UpdateProgress(4, "步骤5: 复制 C# 到 Unity");
                if (!Step5_CopyCSharp(paths))
                {
                    Log("[FAIL] 步骤5失败，终止执行");
                    return;
                }
                
                // 步骤6: 复制 Bytes 到 Unity
                UpdateProgress(5, "步骤6: 复制 Bytes 到 Unity");
                if (!Step6_CopyBytes(paths))
                {
                    Log("[FAIL] 步骤6失败，终止执行");
                    return;
                }
                
                // 步骤7: 生成 DR 文件
                UpdateProgress(6, "步骤7: 生成 DR 文件");
                if (!Step7_GenerateDR(paths))
                {
                    Log("[FAIL] 步骤7失败，终止执行");
                    return;
                }
                
                UpdateProgress(7, "完成");
                
                endTime = DateTime.Now;
                
                // 生成报告
                string report = GenerateReport();
                Log("\n" + report);
                
                // 保存完整日志到 ThriftPipeline/Log 目录
                string logDir = Path.Combine(
                    Application.dataPath,
                    "Editor",
                    "CustomTools",
                    "ThriftPipeline",
                    "Log"
                );
                
                // 确保Log目录存在
                if (!Directory.Exists(logDir))
                {
                    Directory.CreateDirectory(logDir);
                }
                
                // 保存完整日志（详细日志 + 摘要报告）
                string logFileName = $"ThriftPipeline_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
                string logFilePath = Path.Combine(logDir, logFileName);
                
                StringBuilder fullLog = new StringBuilder();
                fullLog.AppendLine("================================================================================");
                fullLog.AppendLine("                       详细执行日志");
                fullLog.AppendLine("================================================================================");
                fullLog.AppendLine();
                fullLog.Append(logBuilder.ToString());
                fullLog.AppendLine();
                fullLog.AppendLine();
                fullLog.Append(report);
                
                File.WriteAllText(logFilePath, fullLog.ToString());
                Log($"\n日志已保存: Log/{logFileName}");
                
                EditorUtility.DisplayDialog("成功", "流程执行完成！", "确定");
            }
            catch (Exception ex)
            {
                Log($"\n[FAIL] 执行失败: {ex.Message}");
                Log(ex.StackTrace);
                EditorUtility.DisplayDialog("错误", $"执行失败:\n{ex.Message}", "确定");
            }
            finally
            {
                isExecuting = false;
                AssetDatabase.Refresh();
                Repaint();
            }
        }
        
        // ========== 步骤1: 生成 Thrift 文件 ==========
        
        private async Task<bool> Step1_GenerateThriftFiles(Dictionary<string, string> paths)
        {
            Log("\n【步骤1】生成 Thrift 文件");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string cfgJsonPath = paths["cfg_json"];
                string configDir = paths["config_dir"];
                string thriftDir = paths["thrift_dir"];
                
                // 读取 cfg_txt.json
                string cfgText = File.ReadAllText(cfgJsonPath);
                var cfg = JsonConvert.DeserializeObject<JObject>(cfgText);
                var fileList = cfg["file_list"] as JArray;
                
                if (fileList == null || fileList.Count == 0)
                {
                    Log("[FAIL] cfg_txt.json 中没有文件配置");
                    AddStepReport("生成Thrift文件", false);
                    return false;
                }
                
                // 创建 thrift 目录
                if (!Directory.Exists(thriftDir))
                    Directory.CreateDirectory(thriftDir);
                
                int generatedCount = 0;
                List<string> structNames = new List<string>();
                
                foreach (JObject configItem in fileList)
                {
                    string inFile = configItem["in_file"]?.ToString();
                string outFile = configItem["out_file"]?.ToString();  // 用这个生成 thrift 名称
                string sheetName = configItem["sheet_name"]?.ToString();
                var columnTypes = configItem["coloum_type"] as JArray;
                
                if (string.IsNullOrEmpty(inFile) || string.IsNullOrEmpty(outFile))
                    continue;
                
                // 从 out_file 获取结构名（与 Python 版本一致）
                string structName = outFile.Replace(".txt", "");
                string excelPath = Path.Combine(configDir, inFile);
                
                if (!File.Exists(excelPath))
                {
                    Log($"  [SKIP] Excel 文件不存在: {inFile}");
                    continue;
                }
                
                Log($"  处理: {inFile} -> {structName}");
                
                // 读取 Excel（如果有 sheet_name 就用，否则用第一个 sheet）
                var (headers, types, comments) = ReadExcelHeaders(excelPath, sheetName, columnTypes);
                
                if (headers == null || headers.Count == 0)
                {
                    Log($"  [SKIP] 无法读取表头: {structName}");
                    continue;
                }
                
                // 生成 thrift 内容
                string thriftContent = GenerateThriftContent(structName, headers, types, comments);
                
                // 写入文件
                string thriftFilePath = Path.Combine(thriftDir, $"{structName}.thrift");
                File.WriteAllText(thriftFilePath, thriftContent);
                
                structNames.Add(structName);
                generatedCount++;
                
                Log($"    [OK] 生成: {structName}.thrift");
            }
                
                // 生成 AllConfigs.thrift
                if (structNames.Count > 0)
                {
                    string allConfigsContent = GenerateAllConfigsContent(structNames);
                    string allConfigsPath = Path.Combine(thriftDir, "AllConfigs.thrift");
                    File.WriteAllText(allConfigsPath, allConfigsContent);
                    Log($"    [OK] 生成: AllConfigs.thrift (包含 {structNames.Count} 个配置)");
                }
                
                // 保存结构名列表供后续步骤使用
                configStructNames = structNames;
                
                Log($"\n生成完成: {generatedCount} 个 thrift 文件");
                AddStepReport("生成Thrift文件", true, new Dictionary<string, object>
                {
                    { "total", generatedCount },
                    { "files", structNames }
                });
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤1失败: {ex.Message}");
                Log(ex.StackTrace);
                AddStepReport("生成Thrift文件", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        /// <summary>
        /// 读取 Excel 表头、类型和注释
        /// 完全复刻 Python 的读取逻辑：跳过空表头列，而不是停止
        /// </summary>
        private (List<string> headers, List<string> types, List<string> comments) ReadExcelHeaders(
            string excelPath, string sheetName, JArray columnTypes)
        {
            try
            {
                FileInfo fileInfo = new FileInfo(excelPath);
                using (ExcelPackage package = new ExcelPackage(fileInfo))
                {
                    // 如果指定了 sheet_name 就用，否则用第一个 sheet（与 Python 版本一致）
                    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($"    [WARN] 工作表 '{sheetName}' 不存在或为空");
                        return (null, null, null);
                    }
                    
                    int maxCols = worksheet.Dimension.End.Column;
                    
                    List<string> headers = new List<string>();
                    List<string> types = new List<string>();
                    List<string> comments = new List<string>();
                    
                    // 只读取 coloum_types 定义的数量（与 Python 版本完全一致）
                    int maxColumns = columnTypes != null && columnTypes.Count > 0 ? columnTypes.Count : maxCols;
                    
                    // Excel 结构（与 Python 版本完全一致）：
                    // 第1行：字段名（表头）
                    // 第2行：注释说明
                    // 第3行开始：数据
                    // EPPlus 索引从 1 开始
                    for (int col = 1; col <= maxCols; col++)
                    {
                        // 读取字段名（第1行）
                        string header = worksheet.Cells[1, col].Value?.ToString() ?? "";
                        
                        // 重要：如果字段名为空，跳过这一列，而不是停止（与 Python 版本一致）
                        if (string.IsNullOrWhiteSpace(header))
                        {
                            continue;
                        }
                        
                        headers.Add(header);
                        
                        // 读取注释（第2行）
                        string comment = worksheet.Cells[2, col].Value?.ToString() ?? "";
                        comments.Add(comment);
                        
                        // 读取类型（从 cfg_txt.json 的 coloum_type）
                        int typeIndex = headers.Count - 1;
                        if (columnTypes != null && typeIndex < columnTypes.Count)
                        {
                            types.Add(columnTypes[typeIndex].ToString());
                        }
                        else
                        {
                            types.Add("string"); // 默认类型
                        }
                        
                        // 达到 coloum_types 定义的数量后停止（关键逻辑）
                        if (headers.Count >= maxColumns)
                        {
                            break;
                        }
                    }
                    
                    Log($"    读取到 {headers.Count} 个有效列");
                    
                    return (headers, types, comments);
                }
            }
            catch (Exception ex)
            {
                Log($"    [ERROR] 读取 Excel 失败: {ex.Message}");
                return (null, null, null);
            }
        }
        
        /// <summary>
        /// 生成 Thrift 文件内容
        /// </summary>
        private string GenerateThriftContent(string structName, List<string> headers, List<string> types, List<string> comments)
        {
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("namespace netstd Byway.Thrift.Data");
            sb.AppendLine();
            sb.AppendLine($"struct {structName}Item");
            sb.AppendLine("{");
            
            // 类型映射
            Dictionary<string, string> typeMap = new Dictionary<string, string>
            {
                { "int", "i32" },
                { "int32", "i32" },
                { "i32", "i32" },
                { "integer", "i32" },
                { "long", "i64" },
                { "int64", "i64" },
                { "i64", "i64" },
                { "float", "double" },
                { "double", "double" },
                { "string", "string" },
                { "str", "string" },
                { "text", "string" },
                { "bool", "bool" },
                { "boolean", "bool" },
                { "i8", "i8" },
                { "i16", "i16" }
            };
            
            for (int i = 0; i < headers.Count; i++)
            {
                string header = SanitizeFieldName(headers[i]);  // 清理字段名
                string fieldType = "string";
                
                if (i < types.Count && !string.IsNullOrEmpty(types[i]))
                {
                    string typeKey = types[i].ToLower().Trim();
                    if (typeMap.ContainsKey(typeKey))
                    {
                        fieldType = typeMap[typeKey];
                    }
                }
                
                string comment = i < comments.Count ? comments[i] : "";
                
                if (!string.IsNullOrEmpty(comment))
                {
                    sb.AppendLine($"\t{i + 1}:{fieldType} {header}, // {comment}");
                }
                else
                {
                    sb.AppendLine($"\t{i + 1}:{fieldType} {header},");
                }
            }
            
            sb.AppendLine("}");
            sb.AppendLine();
            sb.AppendLine($"struct {structName}");
            sb.AppendLine("{");
            sb.AppendLine($"\t1:map<i32,{structName}Item> {structName.ToLower()}s,");
            sb.AppendLine("}");
            
            return sb.ToString();
        }
        
        /// <summary>
        /// 清理并转换字段名为PascalCase（与Thrift生成的C#属性匹配）
        /// 规则：只将第一个字母大写，其余保持不变
        /// 示例: key -> Key, en_US -> En_US, merge_id_list -> Merge_id_list
        /// </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>
        /// 生成 AllConfigs.thrift 内容
        /// </summary>
        private string GenerateAllConfigsContent(List<string> structNames)
        {
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("namespace netstd Byway.Thrift.Data");
            sb.AppendLine();
            
            // 添加所有 include
            foreach (string structName in structNames)
            {
                sb.AppendLine($"include \"{structName}.thrift\"");
            }
            
            sb.AppendLine();
            sb.AppendLine("struct AllConfigs");
            sb.AppendLine("{");
            
            // 添加所有字段（PascalCase命名）
            for (int i = 0; i < structNames.Count; i++)
            {
                string structName = structNames[i];
                sb.AppendLine($"\t{i + 1}:{structName}.{structName} {structName},");
            }
            
            sb.AppendLine("}");
            
            return sb.ToString();
        }
        
        // ========== 步骤2: 编译 Thrift 到 C# ==========
        
        private async Task<bool> Step2_CompileToCSharp(Dictionary<string, string> paths)
        {
            Log("\n【步骤2】编译 Thrift 到 C#");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string compiler = paths["compiler"];
                string thriftDir = paths["thrift_dir"];
                string outputDir = paths["csharp_output_dir"];  // 先生成到Thrift项目的中间目录
                
                // 清空输出目录
                if (Directory.Exists(outputDir))
                {
                    Directory.Delete(outputDir, true);
                }
                Directory.CreateDirectory(outputDir);
                
                // 获取所有 thrift 文件
                string[] thriftFiles = Directory.GetFiles(thriftDir, "*.thrift");
                
                // 过滤：只编译 cfg_txt.json 中定义的配置 + AllConfigs
                var filesToCompile = thriftFiles.Where(f =>
                {
                    string fileName = Path.GetFileNameWithoutExtension(f);
                    return fileName == "AllConfigs" || configStructNames.Contains(fileName);
                }).ToArray();
                
                Log($"  找到 {thriftFiles.Length} 个 thrift 文件");
                Log($"  将编译 {filesToCompile.Length} 个配置文件（过滤了 {thriftFiles.Length - filesToCompile.Length} 个无关文件）");
                Log($"  输出目录: {outputDir}");
                Log("");
                
                int successCount = 0;
                List<string> failedList = new List<string>();
                
                foreach (string thriftFile in filesToCompile)
                {
                    string fileName = Path.GetFileName(thriftFile);
                    Log($"  编译: {fileName}");
                    
                    // 调用 thrift.exe（参数与 Python 版本完全一致）
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName = compiler,
                        Arguments = $"-strict -v -r --gen netstd:unity,serial,async_postfix -out \"{outputDir}\" \"{thriftFile}\"",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true,
                        WorkingDirectory = thriftDir
                    };
                    
                    using (Process process = Process.Start(psi))
                    {
                        string output = await process.StandardOutput.ReadToEndAsync();
                        string error = await process.StandardError.ReadToEndAsync();
                        
                        await Task.Run(() => process.WaitForExit());
                        
                        if (process.ExitCode == 0)
                        {
                            Log($"    [OK] 成功");
                            successCount++;
                        }
                        else
                        {
                            Log($"    [FAIL] 失败");
                            if (!string.IsNullOrEmpty(error))
                                Log($"    错误: {error}");
                            failedList.Add(fileName);
                        }
                    }
                }
                
                // 检查生成的 C# 文件
                string csharpActualDir = Path.Combine(outputDir, "Byway", "Thrift", "Data");
                int csFilesCount = 0;
                if (Directory.Exists(csharpActualDir))
                {
                    csFilesCount = Directory.GetFiles(csharpActualDir, "*.cs").Length;
                    Log($"\n  生成了 {csFilesCount} 个 C# 文件");
                }
                
                Log($"\n编译完成: {successCount}/{filesToCompile.Length}");
                
                AddStepReport("编译到C#", true, new Dictionary<string, object>
                {
                    { "success", successCount },
                    { "failed", failedList.Count },
                    { "total", filesToCompile.Length },
                    { "cs_files_count", csFilesCount }
                });
                
                return successCount > 0;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤2失败: {ex.Message}");
                Log(ex.StackTrace);
                AddStepReport("编译到C#", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        // ========== 步骤3: 生成 Bytes 文件 ==========
        
        private async Task<bool> Step3_GenerateBytes(Dictionary<string, string> paths)
        {
            Log("\n【步骤3】生成 Bytes 文件");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string cfgJsonPath = paths["cfg_json"];
                string configDir = paths["config_dir"];
                string bytesOutputDir = paths["bytes_output_dir"];
                string csharpOutputDir = paths["csharp_output_dir"];
                string unityCSharpDir = paths["unity_csharp_dir"];
                
                // 创建输出目录
                if (!Directory.Exists(bytesOutputDir))
                    Directory.CreateDirectory(bytesOutputDir);
                
                // 临时复制C#文件到Unity以便编译和加载
                Log("  [1/4] 临时复制C#文件到Unity");
                string sourceDir = Path.Combine(csharpOutputDir, "Byway", "Thrift", "Data");
                string targetDir = Path.Combine(unityCSharpDir, "Byway", "Thrift", "Data");
                
                if (!Directory.Exists(sourceDir))
                {
                    Log($"[FAIL] 中间C#目录不存在: {sourceDir}");
                    return false;
                }
                
                if (!Directory.Exists(targetDir))
                    Directory.CreateDirectory(targetDir);
                
                // 复制所有.cs文件（除了Extensions）
                string[] csFiles = Directory.GetFiles(sourceDir, "*.cs", SearchOption.TopDirectoryOnly);
                int copiedCount = 0;
                foreach (string csFile in csFiles)
                {
                    string fileName = Path.GetFileName(csFile);
                    if (fileName.Contains("Extensions.cs"))
                    {
                        Log($"    [SKIP] 跳过: {fileName}");
                        continue;
                    }
                    
                    string destFile = Path.Combine(targetDir, fileName);
                    File.Copy(csFile, destFile, true);
                    copiedCount++;
                }
                
                Log($"    [OK] 已复制 {copiedCount} 个C#文件");
                
                // 等待Unity编译
                Log("  [2/4] 等待Unity编译");
                AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
                await Task.Delay(2000);
                
                // 加载程序集
                Log("  [3/4] 加载程序集并生成bytes");
                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] 找不到程序集");
                    return false;
                }
                
                // 读取配置
                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（关键：使用ToArray而不是GetBuffer）
                Log($"\n  序列化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;
                                
                                // 关键：使用ToArray()获取实际写入的数据（对应Python的getvalue()）
                                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)，可能大部分配置未序列化!");
                                }
                            }
                        }
                    }
                }
                
                // 清理Unity中的临时文件
                Log("  [4/4] 清理临时C#文件");
                if (Directory.Exists(targetDir))
                {
                    try
                    {
                        Directory.Delete(targetDir, true);
                        
                        // 清理空目录
                        string thriftFolder = Path.GetDirectoryName(targetDir);
                        if (Directory.Exists(thriftFolder) && Directory.GetFileSystemEntries(thriftFolder).Length == 0)
                            Directory.Delete(thriftFolder);
                        
                        string bywayFolder = Path.GetDirectoryName(thriftFolder);
                        if (Directory.Exists(bywayFolder) && Directory.GetFileSystemEntries(bywayFolder).Length == 0)
                            Directory.Delete(bywayFolder);
                        
                        AssetDatabase.Refresh();
                        Log($"    [OK] 已清理临时文件");
                    }
                    catch (Exception ex)
                    {
                        Log($"    [WARN] 清理失败: {ex.Message}");
                    }
                }
                
                Log($"\n生成完成: 成功 {successCount} 个配置");
                
                AddStepReport("生成Bytes文件", true, new Dictionary<string, object>
                {
                    { "success", successCount }
                });
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤3失败: {ex.Message}");
                Log(ex.StackTrace);
                AddStepReport("生成Bytes文件", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                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)
                    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)
                        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;
                        int fieldSetCount = 0;
                        
                        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;
                                    
                                    // 处理null值
                                    if (cellValue == null)
                                    {
                                        if (property.PropertyType == typeof(string))
                                        {
                                            convertedValue = "";
                                        }
                                        else if (property.PropertyType.IsValueType)
                                        {
                                            // 值类型（int, bool, double等）设置默认值（0, false, 0.0等）
                                            convertedValue = Activator.CreateInstance(property.PropertyType);
                                        }
                                        else
                                        {
                                            // 引用类型跳过
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        convertedValue = ConvertCellValue(cellValue, property.PropertyType);
                                    }
                                    
                                    property.SetValue(itemInstance, convertedValue);
                                    fieldSetCount++;
                                    
                                    if (fieldName.ToLower() == "id" && convertedValue is int)
                                        idValue = (int)convertedValue;
                                }
                                catch (Exception ex)
                                {
                                    Log($"      [WARN] 行{row} 字段{fieldName}转换失败: {ex.Message}");
                                }
                            }
                            else
                            {
                                // 尝试查找所有属性来调试
                                if (filledItemCount == 0) // 只在第一项时输出
                                {
                                    Log($"      [DEBUG] 未找到属性: {fieldName} (原始: {originalHeader})");
                                    Log($"      [DEBUG] {itemType.Name} 可用属性: {string.Join(", ", itemType.GetProperties().Select(p => p.Name))}");
                                }
                            }
                        }
                        
                        if (filledItemCount == 0)
                        {
                            if (fieldSetCount < headers.Count)
                            {
                                // 找出未设置的字段
                                var unsetFields = new List<string>();
                                for (int i = 0; i < headers.Count; i++)
                                {
                                    var h = headers[i];
                                    var fieldName = SanitizeFieldName(h);
                                    var property = itemType.GetProperty(fieldName);
                                    
                                    if (property == null)
                                    {
                                        unsetFields.Add(h);
                                        continue;
                                    }
                                    
                                    var colIndex = validColumns[i];
                                    var cellValue = worksheet.Cells[row, colIndex].Value;
                                    
                                    // 如果是null且不是string类型，则算作未设置
                                    if (cellValue == null && property.PropertyType != typeof(string))
                                    {
                                        unsetFields.Add(h);
                                    }
                                }
                                
                                Log($"      第一行数据: ID={idValue}, 设置了 {fieldSetCount}/{headers.Count} 个字段" +
                                    (unsetFields.Any() ? $" (未设置: {string.Join(", ", unsetFields)})" : ""));
                            }
                            else
                            {
                                Log($"      第一行数据: ID={idValue}, 设置了 {fieldSetCount}/{headers.Count} 个字段");
                            }
                        }
                        
                        if (idValue.HasValue)
                        {
                            var addMethod = dictType.GetMethod("Add");
                            addMethod.Invoke(dictInstance, new object[] { idValue.Value, itemInstance });
                            filledItemCount++;
                        }
                    }
                }
                
                // 获取字典中的条目数量
                var countProperty = dictType.GetProperty("Count");
                int itemCount = countProperty != null ? (int)countProperty.GetValue(dictInstance) : 0;
                
                // 设置字典属性（格式：首字母大写 + 其余小写 + s，如 Adgiftdatas）
                string dictPropertyName = char.ToUpper(structName[0]) + structName.Substring(1).ToLower() + "s";
                var dictProperty = configType.GetProperty(dictPropertyName);
                if (dictProperty != null)
                {
                    dictProperty.SetValue(configInstance, dictInstance);
                    Log($"    字典属性: {dictPropertyName} = {itemCount} 条");
                }
                else
                {
                    Log($"    [ERROR] 未找到字典属性: {dictPropertyName} (类: {configType.Name})");
                    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;
                    }
                    
                    // 验证__isset标志
                    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();
                        var issetProperty = issetType.GetProperty(structName);
                        if (issetProperty != null)
                        {
                            bool issetValue = (bool)issetProperty.GetValue(issetObj);
                            Log($"    AllConfigs.{structName} = OK (__isset={issetValue})");
                            if (!issetValue)
                            {
                                Log($"    [ERROR] __isset.{structName} = false!");
                                return false;
                            }
                        }
                    }
                }
                else
                {
                    Log($"    [ERROR] AllConfigs中未找到属性: {structName}");
                    return false;
                }
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"    [ERROR] {structName}: {ex.Message}");
                return false;
            }
        }
        
        /// <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;
            }
        }
        
        // ========== 步骤4: 清理冲突文件 ==========
        
        private bool Step4_CleanupExtensions(Dictionary<string, string> paths)
        {
            Log("\n【步骤4】清理冲突的 Extensions 文件");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string csharpOutputDir = paths["csharp_output_dir"];
                string actualDir = Path.Combine(csharpOutputDir, "Byway", "Thrift", "Data");
                
                if (!Directory.Exists(actualDir))
                {
                    Log("  [WARN] C# 目录不存在");
                    return true;
                }
                
                // 查找 AllConfigs.Extensions.cs
                string[] extensionFiles = Directory.GetFiles(actualDir, "*AllConfigs.Extensions.cs", SearchOption.TopDirectoryOnly);
                
                int deletedCount = 0;
                
                foreach (string file in extensionFiles)
                {
                    string fileName = Path.GetFileName(file);
                    Log($"  删除: {fileName}");
                    
                    try
                    {
                        File.Delete(file);
                        deletedCount++;
                        Log($"    [OK] 已删除");
                    }
                    catch (Exception ex)
                    {
                        Log($"    [WARN] 删除失败: {ex.Message}");
                    }
                }
                
                if (deletedCount == 0)
                {
                    Log("  未发现需要删除的 Extensions 文件");
                }
                
                Log($"\n清理完成: 删除 {deletedCount} 个文件");
                
                AddStepReport("清理冲突文件", true, new Dictionary<string, object>
                {
                    { "deleted", deletedCount }
                });
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤4失败: {ex.Message}");
                AddStepReport("清理冲突文件", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        // ========== 步骤5: 复制 C# 到 Unity ==========
        
        private bool Step5_CopyCSharp(Dictionary<string, string> paths)
        {
            Log("\n【步骤5】复制 C# 文件到 Unity");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string csharpOutputDir = paths["csharp_output_dir"];
                string unityCSharpDir = paths["unity_csharp_dir"];
                
                string sourceDir = Path.Combine(csharpOutputDir, "Byway", "Thrift", "Data");
                string targetDir = Path.Combine(unityCSharpDir, "Byway", "Thrift", "Data");
                
                if (!Directory.Exists(sourceDir))
                {
                    Log("  [FAIL] 源目录不存在");
                    return false;
                }
                
                // 创建目标目录
                if (Directory.Exists(targetDir))
                {
                    Directory.Delete(targetDir, true);
                }
                Directory.CreateDirectory(targetDir);
                
                // 复制所有C#文件
                int copiedCount = 0;
                foreach (string file in Directory.GetFiles(sourceDir, "*.cs"))
                {
                    string fileName = Path.GetFileName(file);
                    string destFile = Path.Combine(targetDir, fileName);
                    File.Copy(file, destFile, true);
                    copiedCount++;
                }
                
                Log($"\n复制完成: {copiedCount} 个 C# 文件");
                
                AddStepReport("复制C#到Unity", true, new Dictionary<string, object>
                {
                    { "count", copiedCount }
                });
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤5失败: {ex.Message}");
                Log(ex.StackTrace);
                AddStepReport("复制C#到Unity", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        // ========== 步骤6: 复制 Bytes 到 Unity ==========
        
        private bool Step6_CopyBytes(Dictionary<string, string> paths)
        {
            Log("\n【步骤6】复制 Bytes 文件到 Unity");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                string bytesOutputDir = paths["bytes_output_dir"];
                string unityBytesDir = paths["unity_bytes_dir"];
                
                if (!Directory.Exists(unityBytesDir))
                {
                    Directory.CreateDirectory(unityBytesDir);
                }
                
                // 只复制 AllConfigs.bytes
                string sourceFile = Path.Combine(bytesOutputDir, "AllConfigs.bytes");
                string targetFile = Path.Combine(unityBytesDir, "AllConfigs.bytes");
                
                if (File.Exists(sourceFile))
                {
                    File.Copy(sourceFile, targetFile, true);
                    Log("  [OK] 复制 AllConfigs.bytes");
                    
                    AddStepReport("复制Bytes到Unity", true, new Dictionary<string, object>
                    {
                        { "count", 1 }
                    });
                    return true;
                }
                else
                {
                    Log("  [FAIL] 未找到 AllConfigs.bytes");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤6失败: {ex.Message}");
                AddStepReport("复制Bytes到Unity", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        // ========== 步骤7: 生成 DR 文件 ==========
        
        private bool Step7_GenerateDR(Dictionary<string, string> paths)
        {
            Log("\n【步骤5】生成 DR 文件");
            Log("--------------------------------------------------------------------------------");
            
            try
            {
                // 从Unity项目中读取C#文件（已经复制过来的）
                string unityCSharpDir = paths["unity_csharp_dir"];
                string drOutputDir = paths["dr_output_dir"];
                string actualDir = Path.Combine(unityCSharpDir, "Byway", "Thrift", "Data");
                
                // 创建 DR 输出目录
                if (!Directory.Exists(drOutputDir))
                    Directory.CreateDirectory(drOutputDir);
                
                // 查找所有配置类（不包括 AllConfigs 和 Item 类）
                string[] csFiles = Directory.GetFiles(actualDir, "*.cs");
                
                int generatedCount = 0;
                
                foreach (string csFile in csFiles)
                {
                    string fileName = Path.GetFileName(csFile);
                    
                    // 跳过 ItemItem（数据类）、AllConfigs、Extensions 文件
                    // 注意：PetAirItem.cs 是配置类（应该生成DR），PetAirItemItem.cs 是数据类（不生成DR）
                    if (fileName.EndsWith("ItemItem.cs") || 
                        fileName.Contains("AllConfigs") || 
                        fileName.Contains("Extensions"))
                        continue;
                    
                    // 解析配置类
                    var configInfo = ParseConfigClass(csFile);
                    if (configInfo == null)
                        continue;
                    
                    string className = configInfo["class_name"];
                    Log($"  生成: DR{className}");
                    
                    // 查找对应的 Item 类
                    string itemFileName = configInfo["item_type"] + ".cs";
                    string itemFilePath = Path.Combine(actualDir, itemFileName);
                    
                    if (!File.Exists(itemFilePath))
                    {
                        Log($"    [WARN] 找不到 Item 文件: {itemFileName}");
                        continue;
                    }
                    
                    // 解析 Item 类属性
                    var properties = ParseItemClass(itemFilePath);
                    
                    // 生成 DR 代码
                    string drCode = GenerateDRCode(configInfo, properties);
                    
                    // 写入文件
                    string drFilePath = Path.Combine(drOutputDir, $"DR{configInfo["class_name"]}.cs");
                    File.WriteAllText(drFilePath, drCode);
                    
                    Log($"    [OK] 生成完成");
                    generatedCount++;
                }
                
                Log($"\n生成完成: {generatedCount} 个 DR 文件");
                
                AddStepReport("生成DR文件", true, new Dictionary<string, object>
                {
                    { "total", generatedCount }
                });
                
                return true;
            }
            catch (Exception ex)
            {
                Log($"[FAIL] 步骤5失败: {ex.Message}");
                Log(ex.StackTrace);
                AddStepReport("生成DR文件", false, new Dictionary<string, object>
                {
                    { "error", ex.Message }
                });
                return false;
            }
        }
        
        /// <summary>
        /// 解析配置类文件
        /// </summary>
        private Dictionary<string, string> ParseConfigClass(string filePath)
        {
            try
            {
                string content = File.ReadAllText(filePath);
                
                // 提取类名
                var classMatch = Regex.Match(content, @"public partial class (\w+) : TBase");
                if (!classMatch.Success)
                    return null;
                
                string className = classMatch.Groups[1].Value;
                
                // 提取 Dictionary 属性（支持 global:: 命名空间）
                // 注意：必须匹配公开属性(public Dictionary)，而不是私有字段(_xxx)
                // 使用多行匹配，确保找到完整的属性定义
                var propPattern = @"public\s+Dictionary<int,\s*(?:global::[\w\.]+\.)?(\w+)>\s+(\w+)\s*\{";
                var propMatch = Regex.Match(content, propPattern, RegexOptions.Multiline);
                if (!propMatch.Success)
                {
                    // 如果没找到，记录详细信息用于调试
                    return null;
                }
                
                string itemType = propMatch.Groups[1].Value;
                string dictProperty = propMatch.Groups[2].Value;
                
                return new Dictionary<string, string>
                {
                    { "class_name", className },
                    { "item_type", itemType },
                    { "dict_property", dictProperty }
                };
            }
            catch
            {
                return null;
            }
        }
        
        /// <summary>
        /// 解析 Item 类
        /// </summary>
        private List<Dictionary<string, string>> ParseItemClass(string filePath)
        {
            List<Dictionary<string, string>> properties = new List<Dictionary<string, string>>();
            
            try
            {
                string content = File.ReadAllText(filePath);
                
                // 匹配所有公共属性
                var matches = Regex.Matches(content, @"public\s+(\w+(?:<[^>]+>)?)\s+(\w+)\s*\{");
                
                foreach (Match match in matches)
                {
                    string type = match.Groups[1].Value;
                    string name = match.Groups[2].Value;
                    
                    // 跳过 __isset 和 Isset
                    if (name == "__isset" || name == "Isset")
                        continue;
                    
                    var (finalType, defaultValue) = GetTypeInfo(type);
                    
                    properties.Add(new Dictionary<string, string>
                    {
                        { "type", finalType },
                        { "name", name },
                        { "original_type", type },  // 保存原始类型用于判断
                        { "default", defaultValue }
                    });
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return properties;
        }
        
        /// <summary>
        /// 生成 DR 类代码
        /// </summary>
        private string GenerateDRCode(Dictionary<string, string> configInfo, List<Dictionary<string, string>> properties)
        {
            string className = configInfo["class_name"];
            string itemType = configInfo["item_type"];
            string dictProperty = configInfo["dict_property"];
            
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("// 此文件由 ThriftIntegratedPipeline 自动生成，请勿手动修改");
            sb.AppendLine($"// 配置类: {className}");
            sb.AppendLine($"// 数据类: {itemType}");
            sb.AppendLine();
            sb.AppendLine("using UnityEngine;");
            sb.AppendLine("using Byway.Config;");
            sb.AppendLine("using Byway.Thrift.Data;");
            sb.AppendLine("using UnityGameFramework.Runtime;");
            sb.AppendLine();
            sb.AppendLine("namespace CrazyMaple");
            sb.AppendLine("{");
            sb.AppendLine("    /// <summary>");
            sb.AppendLine($"    /// {className} 数据行");
            sb.AppendLine("    /// </summary>");
            sb.AppendLine($"    public class DR{className} : DataRowBase");
            sb.AppendLine("    {");
            sb.AppendLine($"        private {itemType} _configData;");
            sb.AppendLine();
            
            // Id 属性
            var idProp = properties.FirstOrDefault(p => p["name"].ToLower() == "id");
            sb.AppendLine("        /// <summary>");
            sb.AppendLine("        /// 唯一标识");
            sb.AppendLine("        /// </summary>");
            sb.AppendLine("        public override int Id");
            sb.AppendLine("        {");
            sb.AppendLine("            get");
            sb.AppendLine("            {");
            if (idProp != null)
            {
                sb.AppendLine($"                return _configData?.{idProp["name"]} ?? 0;");
            }
            else
            {
                sb.AppendLine("                return 0;");
            }
            sb.AppendLine("            }");
            sb.AppendLine("        }");
            sb.AppendLine();
            
            // 其他属性
            foreach (var prop in properties)
            {
                string propName = prop["name"];
                
                // 跳过ID字段（已经作为override属性生成）
                if (propName.ToLower() == "id")
                    continue;
                
                string propType = prop["type"];
                string originalType = prop.ContainsKey("original_type") ? prop["original_type"] : propType;
                string defaultValue = prop.ContainsKey("default") ? prop["default"] : "";
                
                if (string.IsNullOrEmpty(defaultValue))
                {
                    var (_, defVal) = GetTypeInfo(propType);
                    defaultValue = defVal;
                }
                
                sb.AppendLine("        /// <summary>");
                sb.AppendLine($"        /// {propName}");
                sb.AppendLine("        /// </summary>");
                
                // 特殊处理：double类型在DR中返回float（与Python版本一致）
                if (originalType.ToLower().Contains("double"))
                {
                    sb.AppendLine($"        public float {propName}");
                    sb.AppendLine("        {");
                    sb.AppendLine("            get");
                    sb.AppendLine("            {");
                    sb.AppendLine($"                return System.Convert.ToSingle(_configData?.{propName} ?? 0.0);");
                    sb.AppendLine("            }");
                    sb.AppendLine("        }");
                }
                else
                {
                    sb.AppendLine($"        public {propType} {propName}");
                    sb.AppendLine("        {");
                    sb.AppendLine("            get");
                    sb.AppendLine("            {");
                    sb.AppendLine($"                return _configData?.{propName} ?? {defaultValue};");
                    sb.AppendLine("            }");
                    sb.AppendLine("        }");
                }
                sb.AppendLine();
            }
            
            // UIForm 特殊处理：使用完整命名空间类型名
            string fullClassName = className == "UIForm" ? "Byway.Thrift.Data.UIForm" : className;
            
            // LoadFromConfig 方法（优化：支持可选的配置实例参数和直接传入 Item）
            sb.AppendLine("        /// <summary>");
            sb.AppendLine("        /// 从配置加载数据（优先使用传入的配置实例）");
            sb.AppendLine("        /// </summary>");
            sb.AppendLine($"        public void LoadFromConfig(int id, {fullClassName} config = null)");
            sb.AppendLine("        {");
            sb.AppendLine("            if (config == null)");
            sb.AppendLine("            {");
            sb.AppendLine($"                config = ConfigManager.Instance.GetConfig<{fullClassName}>();");
            sb.AppendLine("            }");
            sb.AppendLine("            ");
            sb.AppendLine($"            if (config?.{dictProperty} != null)");
            sb.AppendLine("            {");
            sb.AppendLine($"                config.{dictProperty}.TryGetValue(id, out _configData);");
            sb.AppendLine("            }");
            sb.AppendLine("        }");
            sb.AppendLine();
            
            // 添加直接设置 Item 的方法（性能优化）
            sb.AppendLine("        /// <summary>");
            sb.AppendLine("        /// 直接设置配置数据（性能优化：跳过字典查询）");
            sb.AppendLine("        /// </summary>");
            sb.AppendLine($"        public void SetConfigData({itemType} configData)");
            sb.AppendLine("        {");
            sb.AppendLine("            _configData = configData;");
            sb.AppendLine("        }");
            sb.AppendLine();
            
            // ParseDataRow 方法（优化：使用 userData 传入的配置实例，或直接传入 Item）
            sb.AppendLine("        /// <summary>");
            sb.AppendLine("        /// 解析数据行（优化：使用 userData 传入的配置实例，避免重复调用 GetConfig）");
            sb.AppendLine("        /// </summary>");
            sb.AppendLine("        public override bool ParseDataRow(string dataRowString, object userData)");
            sb.AppendLine("        {");
            sb.AppendLine("            int id = 0;");
            sb.AppendLine("            if (!int.TryParse(dataRowString, out id))");
            sb.AppendLine("            {");
            sb.AppendLine("                return false;");
            sb.AppendLine("            }");
            sb.AppendLine();
            sb.AppendLine("            // 性能优化：尝试从 userData 获取配置字典，直接获取 Item");
            sb.AppendLine("            if (userData is System.Collections.Generic.Dictionary<string, object> userDataDict)");
            sb.AppendLine("            {");
            sb.AppendLine("                // 优先尝试从缓存的字典直接获取 Item（最快）");
            sb.AppendLine("                if (userDataDict.TryGetValue(\"ConfigDict\", out object dictObj))");
            sb.AppendLine("                {");
            sb.AppendLine("                    var dict = dictObj as System.Collections.Generic.Dictionary<int, " + itemType + ">;");
            sb.AppendLine("                    if (dict != null && dict.TryGetValue(id, out var item))");
            sb.AppendLine("                    {");
            sb.AppendLine("                        _configData = item;");
            sb.AppendLine("                        return true;");
            sb.AppendLine("                    }");
            sb.AppendLine("                }");
            sb.AppendLine();
            sb.AppendLine("                // 备选方案：从配置实例获取");
            sb.AppendLine("                if (userDataDict.TryGetValue(\"ConfigInstance\", out object configObj))");
            sb.AppendLine("                {");
            sb.AppendLine($"                    var config = configObj as {fullClassName};");
            sb.AppendLine("                    if (config != null)");
            sb.AppendLine("                    {");
            sb.AppendLine("                        LoadFromConfig(id, config);");
            sb.AppendLine("                        return _configData != null;");
            sb.AppendLine("                    }");
            sb.AppendLine("                }");
            sb.AppendLine("            }");
            sb.AppendLine();
            sb.AppendLine("            // 兜底方案：直接查询（最慢）");
            sb.AppendLine("            LoadFromConfig(id);");
            sb.AppendLine("            return _configData != null;");
            sb.AppendLine("        }");
            sb.AppendLine("    }");
            sb.AppendLine("}");
            
            return sb.ToString();
        }
        
        /// <summary>
        /// 获取类型信息和默认值
        /// </summary>
        private (string type, string defaultValue) GetTypeInfo(string csType)
        {
            if (csType.Contains("Dictionary") || csType.Contains("List"))
            {
                return (csType, "null");
            }
            
            switch (csType.ToLower())
            {
                case "int":
                case "i32":
                    return ("int", "0");
                case "long":
                case "i64":
                    return ("long", "0");
                case "double":
                case "float":
                    return ("double", "0.0");
                case "bool":
                case "boolean":
                    return ("bool", "false");
                case "string":
                    return ("string", "\"\"");
                default:
                    return ("string", "\"\"");
            }
        }
        
        // ========== 报告生成 ==========
        
        private string GenerateReport()
        {
            StringBuilder sb = new StringBuilder();
            
            sb.AppendLine("================================================================================");
            sb.AppendLine("                       Thrift 流程执行报告");
            sb.AppendLine("================================================================================");
            sb.AppendLine($"执行时间: {startTime:yyyy-MM-dd HH:mm:ss} -> {endTime:yyyy-MM-dd HH:mm:ss}");
            sb.AppendLine($"总耗时: {(endTime - startTime).TotalSeconds:F2} 秒");
            sb.AppendLine();
            
            // 步骤摘要
            int totalSteps = reportSteps.Count;
            int successSteps = reportSteps.Count(s => s.Success);
            
            sb.AppendLine("步骤摘要:");
            for (int i = 0; i < reportSteps.Count; i++)
            {
                var step = reportSteps[i];
                string status = step.Success ? "[OK]" : "[FAIL]";
                sb.AppendLine($"  {i + 1}. {status} {step.Name}");
            }
            
            sb.AppendLine();
            
            if (successSteps == totalSteps)
            {
                sb.AppendLine("【总体状态】[OK] 所有步骤成功完成，无错误");
            }
            else
            {
                sb.AppendLine($"【总体状态】[WARNING] {totalSteps - successSteps} 个步骤失败");
            }
            
            sb.AppendLine();
            sb.AppendLine("================================================================================");
            sb.AppendLine("                       详细执行报告");
            sb.AppendLine("================================================================================");
            sb.AppendLine();
            
            // 详细步骤信息
            for (int i = 0; i < reportSteps.Count; i++)
            {
                var step = reportSteps[i];
                string status = step.Success ? "[OK]" : "[FAIL]";
                
                sb.AppendLine($"【步骤 {i + 1}】{step.Name}");
                sb.AppendLine($"状态: {status}");
                sb.AppendLine($"时间: {step.Time:HH:mm:ss}");
                sb.AppendLine("--------------------------------------------------------------------------------");
                
                if (step.Details != null && step.Details.Count > 0)
                {
                    foreach (var detail in step.Details)
                    {
                        sb.AppendLine($"  {detail.Key}: {detail.Value}");
                    }
                }
                
                sb.AppendLine();
            }
            
            // 配置路径信息
            sb.AppendLine("================================================================================");
            sb.AppendLine("                       配置路径信息");
            sb.AppendLine("================================================================================");
            
            var paths = GetDerivedPaths();
            
            sb.AppendLine("[基础路径]");
            sb.AppendLine($"  - Docs 项目: {docsProjectPath}");
            sb.AppendLine($"  - Thrift 项目: {thriftProjectPath}");
            sb.AppendLine();
            
            sb.AppendLine("[派生路径]");
            sb.AppendLine($"  - cfg_txt.json: {paths["cfg_json"]}");
            sb.AppendLine($"  - Config 目录: {paths["config_dir"]}");
            sb.AppendLine($"  - Thrift 编译器: {paths["compiler"]}");
            sb.AppendLine($"  - Unity C# 目录: {paths["unity_csharp_dir"]}");
            sb.AppendLine($"  - Unity Bytes 目录: {paths["unity_bytes_dir"]}");
            sb.AppendLine($"  - DR 生成目录: {paths["dr_output_dir"]}");
            sb.AppendLine("================================================================================");
            
            return sb.ToString();
        }
        
        private class StepReport
        {
            public string Name { get; set; }
            public bool Success { get; set; }
            public DateTime Time { get; set; }
            public Dictionary<string, object> Details { get; set; }
        }
    }
}
