from enum import Enum

from pydantic import BaseModel, Field


class LanguageVersion(str, Enum):
    """C# Language versions supported by ILSpy."""

    CSHARP1 = "CSharp1"
    CSHARP2 = "CSharp2"
    CSHARP3 = "CSharp3"
    CSHARP4 = "CSharp4"
    CSHARP5 = "CSharp5"
    CSHARP6 = "CSharp6"
    CSHARP7 = "CSharp7"
    CSHARP7_1 = "CSharp7_1"
    CSHARP7_2 = "CSharp7_2"
    CSHARP7_3 = "CSharp7_3"
    CSHARP8_0 = "CSharp8_0"
    CSHARP9_0 = "CSharp9_0"
    CSHARP10_0 = "CSharp10_0"
    CSHARP11_0 = "CSharp11_0"
    CSHARP12_0 = "CSharp12_0"
    PREVIEW = "Preview"
    LATEST = "Latest"


class EntityType(str, Enum):
    """Entity types that can be listed.

    Accepts both full names and single-letter codes:
    - "class" or "c" for classes
    - "interface" or "i" for interfaces
    - "struct" or "s" for structs
    - "delegate" or "d" for delegates
    - "enum" or "e" for enums
    """

    CLASS = "c"
    INTERFACE = "i"
    STRUCT = "s"
    DELEGATE = "d"
    ENUM = "e"

    @classmethod
    def from_string(cls, value: str) -> "EntityType":
        """Convert a string (full name or single letter) to EntityType.

        Args:
            value: Either a single letter (c, i, s, d, e) or full name (class, interface, etc.)

        Returns:
            The corresponding EntityType enum value

        Raises:
            ValueError: If the value doesn't match any known entity type
        """
        value_lower = value.lower().strip()

        # Map full names to single letters
        name_map = {
            "class": "c",
            "interface": "i",
            "struct": "s",
            "delegate": "d",
            "enum": "e",
        }

        # Convert full name to letter if needed
        if value_lower in name_map:
            value_lower = name_map[value_lower]

        # Try to match against enum values
        for member in cls:
            if member.value == value_lower:
                return member

        valid_options = list(name_map.keys()) + list(name_map.values())
        raise ValueError(f"Invalid entity type: '{value}'. Valid options: {valid_options}")


class DecompileRequest(BaseModel):
    """Request to decompile a .NET assembly."""

    assembly_path: str
    output_dir: str | None = None
    type_name: str | None = None
    language_version: LanguageVersion = LanguageVersion.LATEST
    create_project: bool = False
    show_il_code: bool = False
    reference_paths: list[str] = Field(default_factory=list)
    remove_dead_code: bool = False
    remove_dead_stores: bool = False
    show_il_sequence_points: bool = False
    nested_directories: bool = False


class ListTypesRequest(BaseModel):
    """Request to list types in an assembly."""

    assembly_path: str
    entity_types: list[EntityType] = Field(default_factory=lambda: [EntityType.CLASS])
    reference_paths: list[str] = Field(default_factory=list)


class TypeInfo(BaseModel):
    """Information about a type in an assembly."""

    name: str
    full_name: str
    kind: str
    namespace: str | None = None


class DecompileResponse(BaseModel):
    """Response from decompilation operation."""

    success: bool
    source_code: str | None = None
    output_path: str | None = None
    error_message: str | None = None
    assembly_name: str
    type_name: str | None = None


class ListTypesResponse(BaseModel):
    """Response from list types operation."""

    success: bool
    types: list[TypeInfo] = Field(default_factory=list)
    total_count: int = 0
    error_message: str | None = None


class GenerateDiagrammerRequest(BaseModel):
    """Request to generate HTML diagrammer."""

    assembly_path: str
    output_dir: str | None = None
    include_pattern: str | None = None
    exclude_pattern: str | None = None
    docs_path: str | None = None
    strip_namespaces: list[str] = Field(default_factory=list)
    report_excluded: bool = False


class AssemblyInfoRequest(BaseModel):
    """Request to get assembly information."""

    assembly_path: str


class AssemblyInfo(BaseModel):
    """Information about an assembly."""

    name: str
    version: str
    full_name: str
    location: str
    target_framework: str | None = None
    runtime_version: str | None = None
    is_signed: bool = False
    has_debug_info: bool = False
