// Assets/Editor/DataImporter/CSVToSOImporter.cs

using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;

namespace Northbound.Editor
{
    public static class CSVToSOImporter
    {
        private static readonly string GAMEDATA_PATH = Path.Combine(
            Application.dataPath,
            "..", "GameData"
        );

        private static readonly string SO_BASE_PATH = "Assets/Data/ScriptableObjects";


        public static void ImportAll()
        {
            Debug.Log("=== 전체 데이터 Import 시작 ===");

            var csvFiles = Directory.GetFiles(GAMEDATA_PATH, "*.csv");

            int totalSuccess = 0;
            int totalFail = 0;

            foreach (var csvPath in csvFiles)
            {
                if (csvPath.Contains("Backups"))
                    continue;

                string schemaName = Path.GetFileNameWithoutExtension(csvPath);

                if (schemaName.StartsWith("."))
                    continue;

                Debug.Log($"\n📋 {schemaName} Import 시작...");

                if (ImportSchema(schemaName))
                {
                    totalSuccess++;
                }
                else
                {
                    totalFail++;
                }
            }

            Debug.Log("\n" + new string('=', 60));
            Debug.Log($"🎉 전체 Import 완료: 성공 {totalSuccess}개, 실패 {totalFail}개");
            Debug.Log(new string('=', 60));
        }


        public static bool ImportSchema(string schemaName)
        {
            string csvPath = Path.Combine(GAMEDATA_PATH, $"{schemaName}.csv");
            string outputPath = Path.Combine(SO_BASE_PATH, schemaName);

            if (!File.Exists(csvPath))
            {
                Debug.LogError($"❌ CSV 파일을 찾을 수 없습니다: {csvPath}");
                return false;
            }

            if (!Directory.Exists(outputPath))
            {
                Directory.CreateDirectory(outputPath);
            }

            string className = schemaName + "Data";
            Type dataType = FindScriptableObjectType(className);

            if (dataType == null)
            {
                Debug.LogError($"❌ ScriptableObject 클래스를 찾을 수 없습니다: {className}");
                Debug.LogError($"💡 generate_csharp_classes.py를 먼저 실행하세요.");
                return false;
            }

            Debug.Log($"  ✅ 클래스 발견: {dataType.FullName}");

            int importCount = 0;

            try
            {
                var lines = File.ReadAllLines(csvPath, System.Text.Encoding.UTF8);

                if (lines.Length < 2)
                {
                    Debug.LogError("❌ CSV 파일에 데이터가 없습니다.");
                    return false;
                }

                var headers = ParseCSVLine(lines[0]);

                Debug.Log($"  📊 {lines.Length - 1}개 행, {headers.Length}개 컬럼");

                for (int lineIndex = 1; lineIndex < lines.Length; lineIndex++)
                {
                    string line = lines[lineIndex].Trim();

                    if (string.IsNullOrEmpty(line))
                        continue;

                    try
                    {
                        var values = ParseCSVLine(line);

                        if (values.Length != headers.Length)
                        {
                            Debug.LogWarning($"  ⚠️  행 {lineIndex + 1}: 컬럼 개수 불일치");
                            continue;
                        }

                        var so = ScriptableObject.CreateInstance(dataType);

                        for (int col = 0; col < headers.Length; col++)
                        {
                            string fieldName = headers[col];
                            if (string.IsNullOrEmpty(fieldName))
                                continue;

                            string camelFieldName = ToCamelCase(fieldName);
                            Debug.Log("    🔍 필드 매핑: " + camelFieldName);

                            FieldInfo field = dataType.GetField(camelFieldName, BindingFlags.Public | BindingFlags.Instance);

                            if (field == null)
                            {
                                if (lineIndex == 1)
                                {
                                    Debug.LogWarning($"  ⚠️  필드를 찾을 수 없습니다: {camelFieldName}");
                                }
                                continue;
                            }

                            string cellValue = values[col];
                            SetFieldValue(so, field, cellValue);
                        }

                        string assetName = GetAssetName(so, lineIndex);
                        string fileName = assetName + ".asset";
                        string assetPath = Path.Combine(outputPath, fileName);

                        AssetDatabase.CreateAsset(so, assetPath);
                        importCount++;

                        Debug.Log($"  ✅ {assetName}");
                    }
                    catch (Exception e)
                    {
                        Debug.LogError($"  ❌ 행 {lineIndex + 1} Import 실패: {e.Message}");
                    }
                }

                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();

                Debug.Log($"  🎉 {schemaName} Import 완료: {importCount}개");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"❌ {schemaName} Import 실패: {e.Message}");
                Debug.LogException(e);
                return false;
            }
        }


        private static string[] ParseCSVLine(string line)
        {
            var result = new List<string>();
            bool inQuotes = false;
            string currentValue = "";

            for (int i = 0; i < line.Length; i++)
            {
                char c = line[i];

                if (c == '"')
                {
                    inQuotes = !inQuotes;
                }
                else if (c == ',' && !inQuotes)
                {
                    result.Add(currentValue.Trim());
                    currentValue = "";
                }
                else
                {
                    currentValue += c;
                }
            }

            result.Add(currentValue.Trim());

            return result.ToArray();
        }


        private static Type FindScriptableObjectType(string className)
        {
            string fullName = $"Northbound.Data.{className}";

            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                Type type = assembly.GetType(fullName);
                if (type != null && type.IsSubclassOf(typeof(ScriptableObject)))
                {
                    return type;
                }
            }

            return null;
        }


        private static string ToCamelCase(string snakeCase)
        {
            if (string.IsNullOrEmpty(snakeCase))
                return snakeCase;

            var parts = snakeCase.Split('_');
            if (parts.Length == 1)
                return snakeCase;

            string result = parts[0];
            for (int i = 1; i < parts.Length; i++)
            {
                if (parts[i].Length > 0)
                {
                    result += char.ToUpper(parts[i][0]) + parts[i].Substring(1);
                }
            }

            return result;
        }


        private static void SetFieldValue(object obj, FieldInfo field, string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                field.SetValue(obj, null);
                return;
            }

            Type fieldType = field.FieldType;

            if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                Type underlyingType = Nullable.GetUnderlyingType(fieldType);
                object convertedValue = ConvertValue(value, underlyingType);
                field.SetValue(obj, convertedValue);
            }
            else
            {
                object convertedValue = ConvertValue(value, fieldType);
                field.SetValue(obj, convertedValue);
            }
        }


        private static object ConvertValue(string value, Type targetType)
        {
            if (string.IsNullOrWhiteSpace(value))
                return null;

            if (targetType == typeof(int))
            {
                if (int.TryParse(value, out int result))
                    return result;
                return 0;
            }
            else if (targetType == typeof(float))
            {
                if (float.TryParse(value, out float result))
                    return result;
                return 0f;
            }
            else if (targetType == typeof(double))
            {
                if (double.TryParse(value, out double result))
                    return result;
                return 0.0;
            }
            else if (targetType == typeof(bool))
            {
                string lower = value.ToLower();
                return lower == "true" || lower == "1" || lower == "yes";
            }
            else if (targetType == typeof(string))
            {
                // ⭐ 이스케이프된 줄바꿈 복원
                return value.Replace("\\n", "\n");
            }

            return value;
        }

        private static string GetAssetName(object so, int lineNumber)
        {
            Type type = so.GetType();

            // ⭐ 1순위: id 필드 찾기
            FieldInfo idField = type.GetField("id", BindingFlags.Public | BindingFlags.Instance);
            if (idField != null)
            {
                var idValue = idField.GetValue(so);
                if (idValue != null)
                {
                    // 스키마 이름 추출 (TowersData → Towers, TowerData → Tower)
                    string typeName = type.Name;
                    if (typeName.EndsWith("Data"))
                    {
                        typeName = typeName.Substring(0, typeName.Length - 4);
                    }

                    // Tower1, Enemy5 형식
                    return $"{typeName}{idValue:D3}";
                }
            }

            // ⭐ 2순위: name 필드 찾기
            FieldInfo nameField = type.GetField("name", BindingFlags.Public | BindingFlags.Instance);
            if (nameField != null)
            {
                var nameValue = nameField.GetValue(so);
                if (nameValue != null && !string.IsNullOrWhiteSpace(nameValue.ToString()))
                {
                    string name = nameValue.ToString();
                    name = name.Replace(" ", "");
                    name = System.Text.RegularExpressions.Regex.Replace(name, @"[^a-zA-Z0-9_가-힣]", "");
                    return name;
                }
            }

            // 3순위: 행 번호 사용
            return $"Data_Row{lineNumber}";
        }
    }
}