# DataTools/generate_csharp_classes.py
"""노션 스키마 → Unity C# ScriptableObject 클래스 생성"""

import json
from pathlib import Path
from collections import defaultdict

GAMEDATA_DIR = Path(__file__).parent.parent / "GameData"
UNITY_OUTPUT_DIR = Path(__file__).parent.parent / "Assets" / "Data" / "Scripts" / "DataClasses"


def get_csharp_type(field_type):
    """Python 타입 → C# 타입 변환"""
    type_map = {
        'int': 'int',
        'float': 'float',
        'number': 'float',
        'string': 'string',
        'bool': 'bool',
        'boolean': 'bool'
    }
    return type_map.get(field_type.lower(), 'string')


def to_camel_case(snake_str):
    """
    snake_case → camelCase
    
    예시:
    - tower_type → towerType
    - damage → damage
    - attack_speed → attackSpeed
    """
    components = snake_str.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])


def to_pascal_case(snake_str):
    """
    snake_case → PascalCase
    
    예시:
    - tower_type → TowerType
    - damage → Damage
    """
    return ''.join(x.title() for x in snake_str.split('_'))


def group_fields_by_condition(schema):
    """
    필드를 조건별로 그룹화
    
    반환:
    {
        'common': [공통 필드들],
        'attack': [attack 타입 필드들],
        'defense': [defense 타입 필드들],
        ...
    }
    """
    groups = defaultdict(list)
    
    for field in schema:
        if field.get('condition'):
            condition_value = field['condition']['value']
            groups[condition_value].append(field)
        else:
            groups['common'].append(field)
    
    return groups


def generate_class(schema_name, schema):
    """
    스키마 → C# 클래스 코드 생성
    
    schema: [
        {'name': 'id', 'type': 'int', 'condition': None, 'description': '...'},
        {'name': 'damage', 'type': 'float', 'condition': {...}, 'description': '...'},
        ...
    ]
    """
    class_name = schema_name + "Data"
    
    # 필드 그룹화
    field_groups = group_fields_by_condition(schema)
    
    # 조건 필드명 찾기 (예: tower_type, enemy_type)
    condition_field = None
    for field in schema:
        if field.get('condition'):
            condition_field = field['condition']['field']
            break
    
    # C# 코드 생성 시작
    lines = []
    
    # 파일 헤더
    lines.append("// 이 파일은 자동 생성되었습니다. 직접 수정하지 마세요!")
    lines.append("// 생성 스크립트: DataTools/generate_csharp_classes.py")
    lines.append("")
    lines.append("using UnityEngine;")
    lines.append("")
    lines.append("namespace DigAndDefend.Data")
    lines.append("{")
    lines.append(f'    [CreateAssetMenu(fileName = "{class_name}", menuName = "DigAndDefend/{schema_name} Data")]')
    lines.append(f"    public class {class_name} : ScriptableObject")
    lines.append("    {")
    
    # 공통 필드
    if 'common' in field_groups and field_groups['common']:
        lines.append("        [Header(\"기본 정보\")]")
        for field in field_groups['common']:
            add_field(lines, field, nullable=False)
        lines.append("")
    
    # 조건부 필드 (그룹별)
    for condition_value, fields in field_groups.items():
        if condition_value == 'common':
            continue
        
        header_name = condition_value.capitalize()
        lines.append(f"        [Header(\"{header_name} 전용\")]")
        
        for field in fields:
            add_field(lines, field, nullable=True)
        
        lines.append("")
    
    # 유틸리티 메서드
    if condition_field:
        lines.append("        // ===== 유틸리티 메서드 =====")
        lines.append("")
        
        # 타입 체크 프로퍼티
        for condition_value in field_groups.keys():
            if condition_value == 'common':
                continue
            
            property_name = f"Is{to_pascal_case(condition_value)}"
            field_name = to_camel_case(condition_field)
            
            lines.append(f'        public bool {property_name} => {field_name} == "{condition_value}";')
        
        lines.append("")
        
        # Nullable 필드 Getter 메서드
        for condition_value, fields in field_groups.items():
            if condition_value == 'common':
                continue
            
            for field in fields:
                field_name = to_camel_case(field['name'])
                method_name = f"Get{to_pascal_case(field['name'])}"
                field_type = get_csharp_type(field['type'])
                
                # 기본값 결정
                if field_type == 'int':
                    default_value = '0'
                elif field_type == 'float':
                    default_value = '0f'
                elif field_type == 'bool':
                    default_value = 'false'
                else:
                    default_value = '""'
                
                lines.append(f"        public {field_type} {method_name}() => {field_name} ?? {default_value};")
    
    # 클래스 종료
    lines.append("    }")
    lines.append("}")
    
    return "\n".join(lines)


def add_field(lines, field, nullable=False):
    """필드 정의 추가"""
    field_name = to_camel_case(field['name'])
    field_type = get_csharp_type(field['type'])
    
    # 주석 (설명이 있으면)
    if field.get('description'):
        # 줄바꿈을 공백으로 변환 (C# 주석은 한 줄)
        description = field['description'].replace('\\n', ' ').replace('\n', ' ')
        lines.append(f"        /// <summary>{description}</summary>")
    
    # 필드 선언
    if nullable:
        lines.append(f"        public {field_type}? {field_name};")
    else:
        lines.append(f"        public {field_type} {field_name};")


def generate_all_classes():
    """모든 스키마에 대해 C# 클래스 생성"""
    
    # 출력 폴더 생성
    UNITY_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    
    # 스키마 파일 찾기
    schema_files = list(GAMEDATA_DIR.glob(".*_schema.json"))
    
    if not schema_files:
        print("⚠️  스키마 파일을 찾을 수 없습니다.")
        print("💡 먼저 sync_from_notion.py를 실행하세요.")
        return
    
    print("=" * 60)
    print("🔧 C# 클래스 자동 생성")
    print("=" * 60)
    print()
    
    generated_count = 0
    
    for schema_file in schema_files:
        # ".Towers_schema.json" → "Towers"
        schema_name = schema_file.stem.replace("_schema", "").lstrip(".")
        
        print(f"📋 {schema_name} 처리 중...")
        
        # 스키마 로드
        try:
            with open(schema_file, 'r', encoding='utf-8') as f:
                schema = json.load(f)
        except Exception as e:
            print(f"  ❌ 스키마 로드 실패: {e}")
            continue
        
        # C# 코드 생성
        try:
            csharp_code = generate_class(schema_name, schema)
        except Exception as e:
            print(f"  ❌ 코드 생성 실패: {e}")
            import traceback
            traceback.print_exc()
            continue
        
        # 파일 저장
        output_file = UNITY_OUTPUT_DIR / f"{schema_name}Data.cs"
        try:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(csharp_code)
            
            print(f"  ✅ 생성: {schema_name}Data.cs ({len(schema)}개 필드)")
            generated_count += 1
            
        except Exception as e:
            print(f"  ❌ 파일 저장 실패: {e}")
    
    print()
    print("=" * 60)
    print(f"🎉 완료: {generated_count}개 클래스 생성")
    print(f"📂 위치: {UNITY_OUTPUT_DIR}")
    print("=" * 60)


if __name__ == "__main__":
    generate_all_classes()