#!/usr/bin/env python
"""
Enhanced Type Generator - Generate TypeScript types from Pydantic models
Now with command line parameters, pre-test validation, TypeScript compilation,
automatic date field conversion functions, and proper enum default handling
"""

import sys
import os
import argparse
import subprocess
from typing import Any, Dict, List, Optional, Union, get_origin, get_args
from datetime import datetime
from enum import Enum
from pathlib import Path
import stat

def run_command(command: str, description: str, cwd: str | None = None) -> bool:
    """Run a command and return success status"""
    try:
        result = subprocess.run(
            command, 
            shell=True, 
            capture_output=True, 
            text=True,
            cwd=cwd
        )
        
        if result.returncode == 0:
            print(f"✅ {description}")
            return True
        else:
            print(f"❌ {description} failed:")
            if result.stderr.strip():
                print(f"   Error: {result.stderr.strip()}")
            if result.stdout.strip():
                print(f"   Output: {result.stdout.strip()}")
            return False
            
    except Exception as e:
        print(f"❌ {description} failed with exception: {e}")
        return False

def run_focused_test() -> bool:
    """Run the focused test to validate models before generating types"""
    print("🧪 Running focused test to validate models...")
    
    # Get the directory of the currently executing script
    script_dir = os.path.dirname(os.path.abspath(__file__))
    test_file_path = os.path.join(script_dir, "focused_test.py")
    
    if not os.path.exists(test_file_path):
        print("❌ focused_test.py not found - skipping model validation")
        return False
    
    return run_command(f"python {test_file_path}", "Model validation")

def check_typescript_available() -> bool:
    """Check if TypeScript compiler is available"""
    return run_command("npx tsc --version", "TypeScript version check")

# Add current directory to Python path so we can import models
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, current_dir)

try:
    from pydantic import BaseModel # type: ignore
except ImportError as e:
    print(f"Error importing pydantic: {e}")
    print("Make sure pydantic is installed: pip install pydantic")
    sys.exit(1)

def unwrap_annotated_type(python_type: Any) -> Any:
    """Unwrap Annotated types to get the actual type"""
    # Handle typing_extensions.Annotated and typing.Annotated
    origin = get_origin(python_type)
    args = get_args(python_type)
    
    # Check for Annotated types - more robust detection
    if origin is not None and args:
        origin_str = str(origin)
        if 'Annotated' in origin_str or (hasattr(origin, '__name__') and origin.__name__ == 'Annotated'):
            # Return the first argument (the actual type)
            return unwrap_annotated_type(args[0])  # Recursive unwrap in case of nested annotations
    
    return python_type

def is_date_type(python_type: Any) -> bool:
    """Check if a Python type represents a date/datetime"""
    # Unwrap any annotations first
    python_type = unwrap_annotated_type(python_type)
    
    # Handle Union types (like Optional[datetime])
    origin = get_origin(python_type)
    if origin is Union:
        args = get_args(python_type)
        # Check if any of the union args is a date type (excluding None)
        return any(is_date_type(arg) for arg in args if arg is not type(None))
    
    # Direct datetime check
    if python_type == datetime:
        return True
    
    # Check if it's a datetime type from the datetime module
    if hasattr(python_type, '__module__') and hasattr(python_type, '__name__'):
        module_name = getattr(python_type, '__module__', '')
        type_name = getattr(python_type, '__name__', '')
        
        # Check for datetime module types
        if module_name == 'datetime' and type_name in ('datetime', 'date', 'time'):
            return True
    
    # String representation checks for specific datetime patterns (more restrictive)
    type_str = str(python_type)
    
    # Be very specific about datetime patterns to avoid false positives
    specific_date_patterns = [
        'datetime.datetime',
        'datetime.date', 
        'datetime.time',
        '<class \'datetime.datetime\'>',
        '<class \'datetime.date\'>',
        '<class \'datetime.time\'>',
        'typing.DateTime',
        'pydantic.datetime',
    ]
    
    # Check for exact matches or specific patterns
    for pattern in specific_date_patterns:
        if pattern in type_str:
            return True
    
    # Additional check for common datetime type aliases
    if hasattr(python_type, '__origin__'):
        origin_str = str(python_type.__origin__)
        if 'datetime' in origin_str and 'datetime.' in origin_str:
            return True
    
    return False

def get_default_enum_value(field_info: Any, debug: bool = False) -> Optional[Any]:
    """Extract the specific enum value from a field's default, if it exists"""
    if not hasattr(field_info, 'default'):
        return None
    
    default_val = field_info.default
    
    if debug:
        print(f"         🔍 Checking default value: {repr(default_val)} (type: {type(default_val)})")
    
    # Check for different types of "no default" markers
    if default_val is ... or default_val is None:
        if debug:
            print(f"         └─ Default is undefined marker")
        return None
    
    # Check for Pydantic's internal "PydanticUndefined" or similar markers
    default_str = str(default_val)
    default_type_str = str(type(default_val))
    
    undefined_patterns = [
        'PydanticUndefined', 
        'Undefined', 
        '_Unset',
        'UNSET',
        'NotSet',
        '_MISSING'
    ]
    
    is_undefined_marker = any(pattern in default_str or pattern in default_type_str 
                            for pattern in undefined_patterns)
    
    if is_undefined_marker:
        if debug:
            print(f"         └─ Default is undefined marker pattern")
        return None
    
    # Check if it's an enum instance
    if isinstance(default_val, Enum):
        if debug:
            print(f"         └─ Default is enum instance: {default_val.value}")
        return default_val
    
    if debug:
        print(f"         └─ Default is not an enum instance")
    return None

def python_type_to_typescript(python_type: Any, field_info: Any = None, debug: bool = False) -> str:
    """Convert a Python type to TypeScript type string, considering field defaults"""
    
    if debug:
        print(f"    🔍 Converting type: {python_type} (type: {type(python_type)})")
    
    # First unwrap any Annotated types
    original_type = python_type
    python_type = unwrap_annotated_type(python_type)
    
    if debug and original_type != python_type:
        print(f"    🔄 Unwrapped: {original_type} -> {python_type}")
    
    # FIXED: Don't lock enum types to their default values
    # Instead, always return the full enum type
    if field_info:
        default_enum = get_default_enum_value(field_info, debug)
        if default_enum is not None:
            if debug:
                print(f"    🎯 Field has specific enum default: {default_enum.value}, but returning full enum type")
            # Don't return just the default value - continue to process the full enum type
    
    # Handle None/null
    if python_type is type(None):
        return "null"
    
    # Handle basic types
    if python_type == str:
        return "string"
    elif python_type == int or python_type == float:
        if debug:
            print(f"    ✅ Converting {python_type} to number")
        return "number"
    elif python_type == bool:
        return "boolean"
    elif python_type == dict or python_type == Dict:
        return "Record<string, any>"
    elif python_type == list or python_type == List:
        return "Array<any>"
    
    # Handle typing generics
    origin = get_origin(python_type)
    args = get_args(python_type)
    
    if debug and origin:
        print(f"    🔍 Generic type - origin: {origin}, args: {args}")
    
    if origin is Union:
        # Handle Optional (Union[T, None])
        if len(args) == 2 and type(None) in args:
            non_none_type = next(arg for arg in args if arg is not type(None))
            return python_type_to_typescript(non_none_type, field_info, debug)
        
        # Handle other unions
        union_types = [python_type_to_typescript(arg, None, debug) for arg in args if arg is not type(None)]
        return " | ".join(union_types)
    
    elif origin is list or origin is List:
        if args:
            item_type = python_type_to_typescript(args[0], None, debug)
            return f"Array<{item_type}>"
        return "Array<any>"
    
    elif origin is dict or origin is Dict:
        if len(args) == 2:
            key_type = python_type_to_typescript(args[0], None, debug)
            value_type = python_type_to_typescript(args[1], None, debug)
            return f"Record<{key_type}, {value_type}>"
        return "Record<string, any>"
    
    # Handle Literal types
    if hasattr(python_type, '__origin__') and str(python_type.__origin__).endswith('Literal'):
        if args:
            literal_values = []
            for arg in args:
                if isinstance(arg, Enum):
                    # Handle enum values within literals
                    literal_values.append(f'"{arg.value}"')
                elif isinstance(arg, str):
                    literal_values.append(f'"{arg}"')
                else:
                    literal_values.append(str(arg))
            return " | ".join(literal_values)
    
    # Handle Enum types
    if isinstance(python_type, type) and issubclass(python_type, Enum):
        enum_values = [f'"{v.value}"' for v in python_type]
        return " | ".join(enum_values)
    
    # Handle individual enum instances
    if isinstance(python_type, Enum):
        return f'"{python_type.value}"'
    
    # Handle datetime
    if python_type == datetime:
        return "Date"
    
    # Handle Pydantic models
    if isinstance(python_type, type) and issubclass(python_type, BaseModel):
        return python_type.__name__
    
    # Handle string representations
    type_str = str(python_type)
    if "EmailStr" in type_str:
        return "string"
    elif "HttpUrl" in type_str:
        return "string"
    elif "UUID" in type_str:
        return "string"
    
    # Default fallback
    if debug:
        print(f"    ⚠️  Falling back to 'any' for type: {python_type}")
    return "any"

def snake_to_camel(snake_str: str) -> str:
    """Convert snake_case to camelCase"""
    components = snake_str.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])

def is_field_optional(field_info: Any, field_type: Any, debug: bool = False) -> bool:
    """Determine if a field should be optional in TypeScript"""
    
    if debug:
        print(f"         🔍 Analyzing field optionality:")
    
    # First, check if the type itself is Optional (Union with None)  
    origin = get_origin(field_type)
    args = get_args(field_type)
    is_union_with_none = origin is Union and type(None) in args
    
    if debug:
        print(f"         └─ Type is Optional[T]: {is_union_with_none}")
    
    # If the type is Optional[T], it's always optional regardless of Field settings
    if is_union_with_none:
        if debug:
            print(f"         └─ RESULT: Optional (type is Optional[T])")
        return True
    
    # For non-Optional types, check Field settings and defaults
    
    # Check for default factory (makes field optional)
    has_default_factory = hasattr(field_info, 'default_factory') and field_info.default_factory is not None
    if debug:
        print(f"         └─ Has default factory: {has_default_factory}")
    
    if has_default_factory:
        if debug:
            print(f"         └─ RESULT: Optional (has default factory)")
        return True
    
    # Check the default value - this is the tricky part
    if hasattr(field_info, 'default'):
        default_val = field_info.default
        if debug:
            print(f"         └─ Has default attribute: {repr(default_val)} (type: {type(default_val)})")
        
        # Check for different types of "no default" markers
        # Pydantic uses various markers for "no default"
        if default_val is ...:  # Ellipsis
            if debug:
                print(f"         └─ RESULT: Required (default is Ellipsis)")
            return False
        
        # Check for Pydantic's internal "PydanticUndefined" or similar markers
        default_str = str(default_val)
        default_type_str = str(type(default_val))
        
        # Common patterns for "undefined" in Pydantic
        undefined_patterns = [
            'PydanticUndefined', 
            'Undefined', 
            '_Unset',
            'UNSET',
            'NotSet',
            '_MISSING'
        ]
        
        is_undefined_marker = any(pattern in default_str or pattern in default_type_str 
                                for pattern in undefined_patterns)
        
        if debug:
            print(f"         └─ Checking for undefined markers in: {default_str} | {default_type_str}")
            print(f"         └─ Is undefined marker: {is_undefined_marker}")
        
        if is_undefined_marker:
            if debug:
                print(f"         └─ RESULT: Required (default is undefined marker)")
            return False
        
        # Special case: if field has a specific default value (like enum), it's required
        # because it will always have a value, just not optional for the consumer
        if isinstance(default_val, Enum):
            if debug:
                print(f"         └─ RESULT: Required (has specific enum default: {default_val.value})")
            return False
            
        # FIXED: Fields with actual default values (like [], "", 0) should be REQUIRED
        # because they will always have a value (either provided or the default)
        if debug:
            print(f"         └─ RESULT: Required (has actual default value - field will always have a value)")
        return False  # Changed from True to False
    else:
        if debug:
            print(f"         └─ No default attribute found")
        
        # If no default attribute exists, check Pydantic's required flag
        if hasattr(field_info, 'is_required'):
            try:
                is_required = field_info.is_required()
                if debug:
                    print(f"         └─ is_required(): {is_required}")
                return not is_required
            except:
                if debug:
                    print(f"         └─ is_required() failed")
                pass
        
        # Check the 'required' attribute (Pydantic v1 style)
        if hasattr(field_info, 'required'):
            is_required = field_info.required
            if debug:
                print(f"         └─ required attribute: {is_required}")
            return not is_required
    
    # Default: if type is not Optional and no clear default, it's required (not optional)
    if debug:
        print(f"         └─ RESULT: Required (fallback - no Optional type, no default)")
    return False

def process_pydantic_model(model_class, debug: bool = False) -> Dict[str, Any]:
    """Process a Pydantic model and return TypeScript interface definition"""
    interface_name = model_class.__name__
    properties = []
    date_fields = []  # Track date fields for conversion functions
    
    if debug:
        print(f"  🔍 Processing model: {interface_name}")
    
    # Get fields from the model
    if hasattr(model_class, 'model_fields'):
        # Pydantic v2
        fields = model_class.model_fields
        for field_name, field_info in fields.items():
            if debug:
                print(f"    📝 Field: {field_name}")
                print(f"       Field info: {field_info}")
                print(f"       Default: {getattr(field_info, 'default', 'NO_DEFAULT')}")
            
            # Use alias if available, otherwise convert snake_case to camelCase
            if hasattr(field_info, 'alias') and field_info.alias:
                ts_name = field_info.alias
            else:
                ts_name = snake_to_camel(field_name)
            
            # Get type annotation
            field_type = getattr(field_info, 'annotation', str)
            if debug:
                print(f"       Raw type: {field_type}")
            
            # Check if this is a date field
            is_date = is_date_type(field_type)
            if debug:
                print(f"       📅 Date type check for {ts_name}: {is_date} (type: {field_type})")
            
            if is_date:
                is_optional = is_field_optional(field_info, field_type, debug)
                date_fields.append({
                    'name': ts_name,
                    'optional': is_optional
                })
                if debug:
                    print(f"       🗓️ Date field detected: {ts_name} (optional: {is_optional})")
            elif debug and ('date' in str(field_type).lower() or 'time' in str(field_type).lower()):
                print(f"       ⚠️  Field {ts_name} contains 'date'/'time' but not detected as date type: {field_type}")
            
            # Pass field_info to the type converter for default enum handling
            ts_type = python_type_to_typescript(field_type, field_info, debug)
            
            # Check if optional
            is_optional = is_field_optional(field_info, field_type, debug)
            
            if debug:
                print(f"       TS name: {ts_name}")
                print(f"       TS type: {ts_type}")
                print(f"       Optional: {is_optional}")
                print()
            
            properties.append({
                'name': ts_name,
                'type': ts_type,
                'optional': is_optional
            })
    
    elif hasattr(model_class, '__fields__'):
        # Pydantic v1
        fields = model_class.__fields__
        for field_name, field_info in fields.items():
            if debug:
                print(f"    📝 Field: {field_name} (Pydantic v1)")
                print(f"       Field info: {field_info}")
            
            # Use alias if available, otherwise convert snake_case to camelCase
            if hasattr(field_info, 'alias') and field_info.alias:
                ts_name = field_info.alias
            else:
                ts_name = snake_to_camel(field_name)
            
            field_type = getattr(field_info, 'annotation', getattr(field_info, 'type_', str))
            if debug:
                print(f"       Raw type: {field_type}")
            
            # Check if this is a date field
            is_date = is_date_type(field_type)
            if debug:
                print(f"       📅 Date type check for {ts_name}: {is_date} (type: {field_type})")
            
            if is_date:
                is_optional = is_field_optional(field_info, field_type)
                date_fields.append({
                    'name': ts_name,
                    'optional': is_optional
                })
                if debug:
                    print(f"       🗓️ Date field detected: {ts_name} (optional: {is_optional})")
            elif debug and ('date' in str(field_type).lower() or 'time' in str(field_type).lower()):
                print(f"       ⚠️  Field {ts_name} contains 'date'/'time' but not detected as date type: {field_type}")
            
            # Pass field_info to the type converter for default enum handling
            ts_type = python_type_to_typescript(field_type, field_info, debug)
            
            # For Pydantic v1, check required and default
            is_optional = is_field_optional(field_info, field_type, debug)
            
            if debug:
                print(f"       TS name: {ts_name}")
                print(f"       TS type: {ts_type}")
                print(f"       Optional: {is_optional}")
                print()
            
            properties.append({
                'name': ts_name,
                'type': ts_type,
                'optional': is_optional
            })
    
    return {
        'name': interface_name,
        'properties': properties,
        'date_fields': date_fields
    }

def process_enum(enum_class) -> Dict[str, Any]:
    """Process an Enum and return TypeScript type definition"""
    enum_name = enum_class.__name__
    values = [f'"{v.value}"' for v in enum_class]
    if len(values) == 0:
        raise ValueError(f"Enum class '{enum_name}' has no values.")
    return {
        'name': enum_name,
        'values': " | ".join(values)
    }

def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
    """Generate TypeScript conversion functions for models with date fields"""
    conversion_functions = []
    
    for interface in interfaces:
        interface_name = interface['name']
        date_fields = interface.get('date_fields', [])
        
        if not date_fields:
            continue  # Skip interfaces without date fields
        
        function_name = f"convert{interface_name}FromApi"
        
        # Generate function
        func_lines = [
            f"/**",
            f" * Convert {interface_name} from API response, parsing date fields",
            f" * Date fields: {', '.join([f['name'] for f in date_fields])}",
            f" */",
            f"export function {function_name}(data: any): {interface_name} {{",
            f"  if (!data) return data;",
            f"  ",
            f"  return {{",
            f"    ...data,"
        ]
        
        # Add date field conversions with validation
        for date_field in date_fields:
            field_name = date_field['name']
            is_optional = date_field['optional']
            
            # Add a comment for clarity
            func_lines.append(f"    // Convert {field_name} from ISO string to Date")
            
            if is_optional:
                func_lines.append(f"    {field_name}: data.{field_name} ? new Date(data.{field_name}) : undefined,")
            else:
                func_lines.append(f"    {field_name}: new Date(data.{field_name}),")
        
        func_lines.extend([
            f"  }};",
            f"}}"
        ])
        
        conversion_functions.append('\n'.join(func_lines))
    
    if not conversion_functions:
        return ""
    
    # Generate the conversion functions section
    result = [
        "// ============================",
        "// Date Conversion Functions", 
        "// ============================",
        "",
        "// These functions convert API responses to properly typed objects",
        "// with Date objects instead of ISO date strings",
        "",
    ]
    
    result.extend(conversion_functions)
    result.append("")
    
    # Generate a generic converter function
    models_with_dates = [interface['name'] for interface in interfaces if interface.get('date_fields')]
    
    if models_with_dates:
        result.extend([
            "/**",
            " * Generic converter that automatically selects the right conversion function",
            " * based on the model type",
            " */",
            "export function convertFromApi<T>(data: any, modelType: string): T {",
            "  if (!data) return data;",
            "  ",
            "  switch (modelType) {"
        ])
        
        for model_name in models_with_dates:
            result.append(f"    case '{model_name}':")
            result.append(f"      return convert{model_name}FromApi(data) as T;")
        
        result.extend([
            "    default:",
            "      return data as T;",
            "  }",
            "}",
            "",
            "/**",
            " * Convert array of items using the appropriate converter",
            " */", 
            "export function convertArrayFromApi<T>(data: any[], modelType: string): T[] {",
            "  if (!data || !Array.isArray(data)) return data;",
            "  return data.map(item => convertFromApi<T>(item, modelType));",
            "}",
            ""
        ])
    
    return '\n'.join(result)

def generate_typescript_interfaces(source_file: str, debug: bool = False):
    """Generate TypeScript interfaces from models"""
    
    print(f"📖 Scanning {source_file} for Pydantic models and enums...")
    
    # Import the models module dynamically
    try:
        import importlib.util
        spec = importlib.util.spec_from_file_location("models", source_file)
        if spec is None or spec.loader is None:
            raise ImportError(f"Could not load module from {source_file}")
        
        models_module = importlib.util.module_from_spec(spec)
        sys.modules["models"] = models_module
        spec.loader.exec_module(models_module)
        
    except Exception as e:
        print(f"❌ Error importing {source_file}: {e}")
        return None
    
    interfaces = []
    enums = []
    
    # Scan the models module
    for name in dir(models_module):
        obj = getattr(models_module, name)
        
        # Skip private attributes
        if name.startswith('_'):
            continue
        
        try:
            # Check if it's a Pydantic model
            if (isinstance(obj, type) and 
                issubclass(obj, BaseModel) and 
                obj != BaseModel):
                
                interface = process_pydantic_model(obj, debug)
                interfaces.append(interface)
                date_count = len(interface.get('date_fields', []))
                print(f"  ✅ Found Pydantic model: {name}" + (f" ({date_count} date fields)" if date_count > 0 else ""))
            
            # Check if it's an Enum
            elif (isinstance(obj, type) and 
                  issubclass(obj, Enum)):
                
                enum_def = process_enum(obj)
                enums.append(enum_def)
                print(f"  ✅ Found enum: {name}")
                
        except Exception as e:
            print(f"  ⚠️  Warning: Error processing {name}: {e}")
            if debug:
                import traceback
                traceback.print_exc()
            continue
    
    total_date_fields = sum(len(interface.get('date_fields', [])) for interface in interfaces)
    print(f"\n📊 Found {len(interfaces)} interfaces and {len(enums)} enums")
    print(f"🗓️  Found {total_date_fields} date fields across all models")
    
    # Generate TypeScript content
    ts_content = f"""// Generated TypeScript types from Pydantic models
// Source: {source_file}
// Generated on: {datetime.now().isoformat()}
// DO NOT EDIT MANUALLY - This file is auto-generated

"""
    
    # Add enums
    if enums:
        ts_content += "// ============================\n"
        ts_content += "// Enums\n"
        ts_content += "// ============================\n\n"
        
        for enum_def in enums:
            ts_content += f"export type {enum_def['name']} = {enum_def['values']};\n\n"
    
    # Add interfaces
    if interfaces:
        ts_content += "// ============================\n"
        ts_content += "// Interfaces\n"
        ts_content += "// ============================\n\n"
        
        for interface in interfaces:
            ts_content += f"export interface {interface['name']} {{\n"
            
            for prop in interface['properties']:
                optional_marker = "?" if prop['optional'] else ""
                ts_content += f"  {prop['name']}{optional_marker}: {prop['type']};\n"
            
            ts_content += "}\n\n"
    
    # Add conversion functions
    conversion_functions = generate_conversion_functions(interfaces)
    if conversion_functions:
        ts_content += conversion_functions
    
    # Add user union type if we have user types
    user_interfaces = [i for i in interfaces if i['name'] in ['Candidate', 'Employer', 'Viewer']]
    if len(user_interfaces) >= 2:
        ts_content += "// ============================\n"
        ts_content += "// Union Types\n"
        ts_content += "// ============================\n\n"
        user_type_names = [i['name'] for i in user_interfaces]
        ts_content += f"export type User = {' | '.join(user_type_names)};\n\n"
    
    # Add export statement
    ts_content += "// Export all types\n"
    ts_content += "export type { };\n"
    
    return ts_content

def compile_typescript(ts_file: str) -> bool:
    """Compile TypeScript file to check for syntax errors"""
    print(f"🔧 Compiling TypeScript file to check syntax...")
    
    # Check if TypeScript is available
    if not check_typescript_available():
        print("⚠️  TypeScript compiler not available - skipping compilation check")
        print("   To install: npm install -g typescript")
        return True  # Don't fail if TS isn't available
    
    # Run TypeScript compiler in check mode
    return run_command(
        f"npx tsc --noEmit --skipLibCheck {ts_file}",
        "TypeScript syntax validation"
    )

def main():
    """Main function with command line argument parsing"""
    parser = argparse.ArgumentParser(
        description='Generate TypeScript types from Pydantic models with date conversion functions and proper enum handling',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python generate_types.py                                    # Use defaults
  python generate_types.py --source models.py --output types.ts  # Specify files
  python generate_types.py --skip-test                       # Skip model validation
  python generate_types.py --skip-compile                    # Skip TS compilation
  python generate_types.py --debug                           # Enable debug output
  python generate_types.py --source models.py --output types.ts --skip-test --skip-compile --debug

Generated conversion functions can be used like:
  const candidate = convertCandidateFromApi(apiResponse);
  const jobs = convertArrayFromApi<Job>(apiResponse, 'Job');

Enum types are now properly handled:
  status: ApiStatusType = ApiStatusType.DONE  ->  status: ApiStatusType (not locked to "done")
        """
    )
    
    parser.add_argument(
        '--source', '-s',
        default='models.py',
        help='Source Python file with Pydantic models (default: models.py)'
    )
    
    parser.add_argument(
        '--output', '-o',
        default='types.ts',
        help='Output TypeScript file (default: types.ts)'
    )
    
    parser.add_argument(
        '--skip-test',
        action='store_true',
        help='Skip running focused_test.py before generation'
    )
    
    parser.add_argument(
        '--skip-compile',
        action='store_true',
        help='Skip TypeScript compilation check after generation'
    )
    
    parser.add_argument(
        '--debug',
        action='store_true',
        help='Enable debug output to troubleshoot type conversion issues'
    )
    
    parser.add_argument(
        '--version', '-v',
        action='version',
        version='TypeScript Generator 3.2 (Fixed Enum Default Handling)'
    )
    
    args = parser.parse_args()
    
    print("🚀 Enhanced TypeScript Type Generator with Fixed Enum Handling")
    print("=" * 60)
    print(f"📁 Source file: {args.source}")
    print(f"📁 Output file: {args.output}")
    print()
    
    try:
        # Step 1: Validate source file exists
        if not os.path.exists(args.source):
            print(f"❌ Source file '{args.source}' not found")
            sys.exit(1)
        
        # Step 2: Run focused test (unless skipped)
        if not args.skip_test:
            if not run_focused_test():
                print("❌ Model validation failed - aborting type generation")
                sys.exit(1)
            print()
        else:
            print("⏭️  Skipping model validation test")
            print()
        
        # Step 3: Generate TypeScript content
        print("🔄 Generating TypeScript types and conversion functions...")
        if args.debug:
            print("🐛 Debug mode enabled - detailed output follows:")
            print()
        
        ts_content = generate_typescript_interfaces(args.source, args.debug)
        
        if ts_content is None:
            print("❌ Failed to generate TypeScript content")
            sys.exit(1)
        
        # Step 4: Write to output file
        with open(args.output, 'w') as f:
            f.write(ts_content)
        # Set read-only permissions (owner can read, others can read)
        os.chmod(args.output, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
        
        file_size = len(ts_content)
        print(f"✅ TypeScript types generated: {args.output} ({file_size} characters)")
        
        # Count conversion functions and provide detailed feedback
        conversion_count = ts_content.count('export function convert') - ts_content.count('convertFromApi') - ts_content.count('convertArrayFromApi')
        enum_type_count = ts_content.count('export type')
        
        if conversion_count > 0:
            print(f"🗓️  Generated {conversion_count} date conversion functions")
        if enum_type_count > 0:
            print(f"🎯 Generated {enum_type_count} enum types (properly allowing all values)")
            
        if args.debug:
            # Show which models have date conversion
            models_with_dates = []
            for line in ts_content.split('\n'):
                if line.startswith('export function convert') and 'FromApi' in line and 'convertFromApi' not in line:
                    model_name = line.split('convert')[1].split('FromApi')[0]
                    models_with_dates.append(model_name)
            if models_with_dates:
                print(f"   Models with date conversion: {', '.join(models_with_dates)}")
                    
        # Provide troubleshooting info if debug mode
        if args.debug:
            print(f"\n🐛 Debug mode was enabled. If you see incorrect type conversions:")
            print(f"   1. Check the debug output above for enum default handling")
            print(f"   2. Look for '📅 Date type check' lines for date handling")
            print(f"   3. Look for '⚠️' warnings about fallback types") 
            print(f"   4. Verify your Pydantic model field types and defaults are correct")
        
        # Step 5: Compile TypeScript (unless skipped)
        if not args.skip_compile:
            print()
            if not compile_typescript(args.output):
                print("❌ TypeScript compilation failed - check the generated file")
                sys.exit(1)
        else:
            print("⏭️  Skipping TypeScript compilation check")
        
        # Step 6: Success summary
        print(f"\n🎉 Type generation completed successfully!")
        print("=" * 60)
        print(f"✅ Generated {args.output} from {args.source}")
        print(f"✅ File size: {file_size} characters")
        if conversion_count > 0:
            print(f"✅ Date conversion functions: {conversion_count}")
        if enum_type_count > 0:
            print(f"✅ Enum types (with full value range): {enum_type_count}")
        if not args.skip_test:
            print("✅ Model validation passed")
        if not args.skip_compile:
            print("✅ TypeScript syntax validated")
        
        print(f"\n💡 Usage in your TypeScript project:")
        print(f"   import {{ Candidate, Employer, Job, convertCandidateFromApi }} from './{Path(args.output).stem}';")
        if conversion_count > 0:
            print(f"   const candidate = convertCandidateFromApi(apiResponse);")
            print(f"   const jobs = convertArrayFromApi<Job>(apiResponse, 'Job');")
        
        return True
        
    except KeyboardInterrupt:
        print(f"\n⏹️  Type generation cancelled by user")
        return False
        
    except Exception as e:
        print(f"\n❌ Error generating types: {e}")
        import traceback
        traceback.print_exc()
        return False

if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)