"""
Converter for deprecated raiconfig.toml to RAI Config format.
"""

from __future__ import annotations

from typing import Any

from .raiconfig_models import RAIConfigFile, RAIConfigSnowflakeProfile, RAIConfigLocalProfile


# Central field mapping configuration
# Format: "old_field_name": ("new_section", "new_field_name")
# where section=None means top-level field
FIELD_MAPPINGS = {
    # Top-level fields (stay at top level)
    "use_graph_index": (None, "use_graph_index"),
    "use_direct_access": (None, "use_direct_access"),
    "enable_otel_handler": (None, "enable_otel_handler"),
    "use_package_manager": (None, "use_package_manager"),
    "reuse_model": (None, "reuse_model"),
    "skip_invalid_data": (None, "skip_invalid_data"),

    # Engine fields
    "engine": ("engine", "name"),
    "engine_size": ("engine", "size"),
    "auto_suspend_mins": ("engine", "auto_suspend_mins"),

    # Data fields
    "wait_for_stream_sync": ("data", "wait_for_stream_sync"),
    "ensure_change_tracking": ("data", "ensure_change_tracking"),
    "data_freshness_mins": ("data", "data_freshness_mins"),
    "query_timeout_mins": ("data", "query_timeout_mins"),
    "download_url_type": ("data", "download_url_type"),

    # Debug fields
    "debug": ("debug", "enabled"),  # Note: maps to "enabled"!
    "show_full_traces": ("debug", "show_full_traces"),

    # Compiler fields
    "use_monotype_operators": ("compiler", "use_monotype_operators"),
    "show_corerel_errors": ("compiler", "show_corerel_errors"),
    "dry_run": ("compiler", "dry_run"),
    "inspect_df": ("compiler", "inspect_df"),
    "use_value_types": ("compiler", "use_value_types"),
    "debug_hidden_keys": ("compiler", "debug_hidden_keys"),
    "wide_outputs": ("compiler", "wide_outputs"),
    "strict": ("compiler", "strict"),
    "use_inlined_intermediates": ("compiler", "use_inlined_intermediates"),
    "inline_value_maps": ("compiler", "inline_value_maps"),
    "inline_entity_maps": ("compiler", "inline_entity_maps"),

    # Model fields
    "keep": ("model", "keep"),
    "isolated": ("model", "isolated"),
    "nowait_durable": ("model", "nowait_durable"),
}

# Connection fields (stay in connection dict)
CONNECTION_FIELDS = {
    "account", "warehouse", "user", "password", "role", "database", "schema",
    "authenticator", "rai_app_name", "passcode",
    "private_key_path", "private_key_passphrase", "token",
}

# Old -> New field name mappings for connection fields
# Old field names from deprecated raiconfig.toml are mapped to new names
# These are accessed via model_extra in RAIConfigSnowflakeProfile.convert()
CONNECTION_FIELD_MAPPINGS = {
    "private_key_file": "private_key_path",
    "private_key_file_pwd": "private_key_passphrase",
    "token_file_path": "token",
}


def map_fields_to_nested_structure(merged: dict[str, Any]) -> dict[str, Any]:
    """
    Map flat config fields to nested structure using FIELD_MAPPINGS.

    This replaces all the manual if statements!

    Args:
        merged: Flat dictionary with all config fields

    Returns:
        Nested dictionary structured according to new config format
    """
    result = {}
    nested_sections = {}  # Collect fields for each section

    for old_field, (section, new_field) in FIELD_MAPPINGS.items():
        if old_field not in merged or merged[old_field] is None:
            continue  # Skip missing or None values

        value = merged[old_field]

        if section is None:
            # Top-level field
            result[new_field] = value
        else:
            # Nested section field
            if section not in nested_sections:
                nested_sections[section] = {}
            nested_sections[section][new_field] = value

    # Add nested sections to result
    for section, fields in nested_sections.items():
        if fields:  # Only add non-empty sections
            result[section] = fields

    return result


def merge_profile_with_toplevel(
    config_file: RAIConfigFile,
    profile: RAIConfigSnowflakeProfile | RAIConfigLocalProfile
) -> dict[str, Any]:
    """
    Merge profile over top-level config (profile takes precedence).

    This matches the v0 behavior where profile-specific settings override
    global defaults.
    """
    # Start with top-level config
    merged = config_file.model_dump(
        exclude={"profile", "active_profile"},
        exclude_none=True
    )

    # Overlay profile fields (they take precedence)
    profile_dict = profile.model_dump(exclude_none=True)

    # Merge profile into config (profile overrides top-level)
    merged.update(profile_dict)

    return merged


def convert_raiconfig_to_rai(
    rai_config: dict[str, Any],
    profile_name: str | None = None
) -> dict[str, Any]:
    """
    Convert deprecated raiconfig.toml to new RAI Config format.

    Flow:
    1. Validate with RAIConfigFile model
    2. Select active profile (parameter > active_profile > single profile)
    3. Merge profile over top-level config (profile takes precedence)
    4. Extract connection from profile
    5. Map flat fields to nested structure

    Args:
        rai_config: Parsed TOML config dict
        profile_name: Profile name to use (overrides active_profile)

    Returns:
        Dict in new config format ready for RAIConfig model
    """
    config_file = RAIConfigFile(**rai_config)

    # Profile selection logic
    if not profile_name:
        profile_name = config_file.active_profile

    # Supported platforms
    supported_platforms = {"snowflake", "local"}

    # Filter to supported profiles (Snowflake and Local)
    supported_profiles = {
        name: data for name, data in config_file.profile.items()
        if data.get("platform", "snowflake") in supported_platforms
    }

    if not profile_name and len(supported_profiles) == 1:
        # Auto-select single supported profile
        profile_name = next(iter(supported_profiles.keys()))

    if not profile_name:
        if not supported_profiles:
            raise ValueError(
                "No supported profiles found in raiconfig.toml. "
                "Supported platforms: snowflake, local. "
                "Please add a supported profile or migrate to raiconfig.yaml."
            )
        raise ValueError(
            f"No profile specified. Either set 'active_profile' in config, "
            f"provide profile_name parameter, or ensure only one supported profile exists. "
            f"Available profiles: {list(supported_profiles.keys())}"
        )

    if profile_name not in config_file.profile:
        available = list(config_file.profile.keys())
        raise ValueError(
            f"Profile '{profile_name}' not found. Available profiles: {available}"
        )

    # Get profile data
    profile_data = config_file.profile[profile_name]
    platform = profile_data.get("platform", "snowflake")

    # Validate and convert based on platform
    if platform == "local":
        profile = RAIConfigLocalProfile(**profile_data)
        connection = profile.convert()
        connection_name = "local"
    elif platform == "snowflake":
        profile = RAIConfigSnowflakeProfile(**profile_data)
        connection = profile.convert()
        connection_name = "snowflake"
    else:
        raise ValueError(
            f"Profile '{profile_name}' uses platform '{platform}'. "
            f"Supported platforms: snowflake, local. "
            f"Please use a supported profile or migrate to raiconfig.yaml."
        )

    # Merge profile with top-level config
    merged = merge_profile_with_toplevel(config_file, profile)

    # Build base result
    result = {
        "connections": {connection_name: connection},
        "default_connection": connection_name,
    }

    # Map all config fields automatically using FIELD_MAPPINGS
    mapped_fields = map_fields_to_nested_structure(merged)
    result.update(mapped_fields)

    # Handle reasoner separately (nested dict structure)
    if "reasoner" in merged and merged["reasoner"]:
        result["reasoner"] = merged["reasoner"]

    return result
