from typing import Type

from pydantic import create_model, Field as PydanticField, BaseModel

from belso.schemas import Schema, Field
from belso.utils.logging import get_logger
from belso.utils.schema_helpers import create_fallback_schema

# Replace standard logger with our custom logger
logger = get_logger(__name__)

def to_openai(schema: Type[Schema]) -> Type:
    """
    Translate a standard schema to OpenAI GPT format (Pydantic model).\n
    ---
    ### Args
    - `schema`: the schema to translate.\n
    ---
    ### Returns
    - `Type`: the translated schema as a Pydantic model.
    """
    try:
        schema_name = schema.__name__ if hasattr(schema, "__name__") else "unnamed"
        logger.debug(f"Starting translation of schema '{schema_name}' to OpenAI format...")

        field_definitions = {}

        # Build field definitions for Pydantic model
        for field in schema.fields:
            field_type = field.type
            logger.debug(f"Processing field '{field.name}' of type '{field_type.__name__}'...")

            if not field.required and field.default is not None:
                logger.debug(f"Field '{field.name}' is optional with default value: {field.default}.")
                field_definitions[field.name] = (field_type, PydanticField(default=field.default, description=field.description))
            else:
                required_status = "required" if field.required else "optional without default"
                logger.debug(f"Field '{field.name}' is {required_status}.")
                field_definitions[field.name] = (field_type, PydanticField(description=field.description))

        # Create a Pydantic model dynamically
        model_name = schema.__name__ if hasattr(schema, "__name__") else "DynamicModel"
        logger.debug(f"Creating Pydantic model '{model_name}' with {len(field_definitions)} fields...")
        pydantic_model = create_model(model_name, **field_definitions)

        logger.debug(f"Successfully created OpenAI schema as Pydantic model '{pydantic_model.__name__}'.")
        return pydantic_model

    except Exception as e:
        logger.error(f"Error translating schema to OpenAI format: {e}")
        logger.debug("Translation error details", exc_info=True)
        # Return a simple fallback model if translation fails
        logger.warning("Returning fallback model due to translation error.")
        return create_model("FallbackModel", text=(str, ...))

def from_openai(schema: Type[BaseModel]) -> Type[Schema]:
    """
    Convert an OpenAI schema (Pydantic model) to belso Schema format.\n
    ---
    ### Args
    - `schema`: the schema to convert.\n
    ---
    ### Returns
    - `Type`: the converted schema as a standard Schema subclass.
    """
    try:
        schema_name = schema.__name__ if hasattr(schema, "__name__") else "unnamed"
        logger.debug(f"Starting conversion from OpenAI schema '{schema_name}' to belso format...")

        # Create a new Schema class
        class ConvertedSchema(Schema):
            name = schema.__name__ if hasattr(schema, "__name__") else "ConvertedFromOpenAI"
            fields = []

        # Get model fields from Pydantic model
        model_fields = schema.model_fields if hasattr(schema, "model_fields") else {}

        # For older Pydantic versions
        if not model_fields and hasattr(schema, "__fields__"):
            logger.debug("Using legacy Pydantic v1 field access.")
            model_fields = schema.__fields__

        logger.debug(f"Found {len(model_fields)} fields in Pydantic model.")

        # Process each field
        for name, field_info in model_fields.items():
            logger.debug(f"Processing field '{name}'.")

            # Extract field type
            if hasattr(field_info, "annotation"):
                field_type = field_info.annotation
                logger.debug(f"Field '{name}' has type annotation: {field_type}")
            elif hasattr(field_info, "type_"):
                field_type = field_info.type_
                logger.debug(f"Field '{name}' has type_: {field_type}")
            else:
                field_type = str  # Default to string
                logger.debug(f"Field '{name}' has no type information, defaulting to str.")

            # Extract description
            description = ""
            if hasattr(field_info, "description"):
                description = field_info.description
                logger.debug(f"Field '{name}' has description: '{description}'.")

            # Extract required status
            required = True
            if hasattr(field_info, "default") and field_info.default is not None:
                required = False
                logger.debug(f"Field '{name}' is optional with default value.")

            # Extract default value
            default = None
            if hasattr(field_info, "default") and field_info.default is not None:
                default = field_info.default
                logger.debug(f"Field '{name}' has default value: {default}.")

            ConvertedSchema.fields.append(
                Field(
                    name=name,
                    type=field_type,
                    description=description,
                    required=required,
                    default=default
                )
            )

        logger.debug(f"Successfully converted OpenAI schema to belso schema with {len(ConvertedSchema.fields)} fields.")
        return ConvertedSchema

    except Exception as e:
        logger.error(f"Error converting OpenAI schema to belso format: {e}")
        logger.debug("Conversion error details", exc_info=True)
        # Return a minimal schema if conversion fails
        return create_fallback_schema()
