"""PostgreSQL ODBC connection configuration."""

import logging

from pydantic import Field, PrivateAttr

from data_exchange_agent.config.sections.connections.odbc.base import (
    BaseODBCConnectionConfig,
)
from data_exchange_agent.constants.connection_types import ConnectionType


logger = logging.getLogger(__name__)


# Connection string template for PostgreSQL ODBC
POSTGRESQL_CONNECTION_STRING = (
    "DRIVER={{{driver}}};"
    "SERVER={server};"
    "PORT={port};"
    "DATABASE={database};"
    "UID={user};"
    "PWD={password}"
)

# Default PostgreSQL port
DEFAULT_POSTGRESQL_PORT = 5432

# Default ODBC driver for PostgreSQL
DEFAULT_POSTGRESQL_DRIVER = "PostgreSQL Unicode"


class PostgresqlConnectionConfig(BaseODBCConnectionConfig):
    """
    Configuration class for PostgreSQL ODBC connection settings.

    Supports standard username/password authentication via ODBC.

    References:
        - https://odbc.postgresql.org/docs/config.html
        - https://www.postgresql.org/docs/current/auth-methods.html

    """

    # Override parent fields with PostgreSQL-specific defaults
    driver_name: str = Field(
        default=ConnectionType.POSTGRESQL, description="Driver name"
    )
    host: str = Field(default="localhost", description="Database host address")
    port: int = Field(
        default=DEFAULT_POSTGRESQL_PORT,
        ge=1,
        le=65535,
        description="Database port number",
    )
    username: str = Field(default="", description="Database username")
    password: str = Field(default="", description="Database password")

    # PostgreSQL-specific fields
    requested_odbc_driver: str | None = Field(
        default=None,
        alias="odbc_driver",
        description="ODBC driver name (auto-detected if not specified)",
    )
    auto_detect_driver: bool = Field(
        default=True, description="Auto-detect the best available ODBC driver"
    )
    ssl_mode: str | None = Field(
        default=None,
        description="SSL mode (disable, allow, prefer, require, verify-ca, verify-full)",
    )

    # Private attributes for internal state
    _resolved_odbc_driver: str = PrivateAttr()

    @property
    def odbc_driver(self) -> str:
        """Get the resolved ODBC driver name."""
        return self._resolved_odbc_driver

    def model_post_init(self, __context) -> None:
        """Post-initialization setup."""
        self._resolved_odbc_driver = self._select_odbc_driver(
            self.requested_odbc_driver, self.auto_detect_driver
        )

    def build_connection_string(self) -> str:
        """Build the ODBC connection string for PostgreSQL."""
        connection_string = POSTGRESQL_CONNECTION_STRING.format(
            driver=self._resolved_odbc_driver,
            server=self.host,
            port=self.port,
            database=self.database,
            user=self.username,
            password=self.password,
        )

        # Add SSL mode if specified
        if self.ssl_mode:
            connection_string += f";SSLMode={self.ssl_mode}"

        # Add extra options
        for key, value in self.extra_options.items():
            stripped_key = str(key).strip()
            stripped_value = str(value).strip()
            connection_string += f";{stripped_key}={stripped_value}"

        return connection_string

    @classmethod
    def from_config_dict(
        cls,
        database: str,
        username: str,
        host: str = "localhost",
        password: str = "",
        port: int = DEFAULT_POSTGRESQL_PORT,
        odbc_driver: str | None = None,
        auto_detect_driver: bool = True,
        ssl_mode: str | None = None,
        **extra_options: str | int | float | bool,
    ) -> "PostgresqlConnectionConfig":
        """
        Create a PostgresqlConnectionConfig from a flat configuration dictionary.

        This factory method is used by the TOML configuration loader to construct
        a PostgresqlConnectionConfig from flat parameters read from the configuration file.

        Args:
            database: Database name
            username: Username for the database
            host: Hostname (default: localhost)
            password: Password
            port: Port number (default: 5432)
            odbc_driver: ODBC driver name (optional)
            auto_detect_driver: Whether to auto-detect the ODBC driver (default: True)
            ssl_mode: SSL mode (optional)
            **extra_options: Extra options to add to the ODBC connection string

        Returns:
            PostgresqlConnectionConfig: Configured connection instance

        """
        return cls(
            driver_name=ConnectionType.POSTGRESQL,
            username=username,
            password=password,
            database=database,
            host=host,
            port=port,
            odbc_driver=odbc_driver,
            auto_detect_driver=auto_detect_driver,
            ssl_mode=ssl_mode,
            extra_options=dict(extra_options),
        )

    def _select_odbc_driver(
        self, requested_driver: str | None, auto_detect: bool
    ) -> str:
        """
        Select the appropriate ODBC driver for PostgreSQL.

        Args:
            requested_driver: The driver requested by the user (can be None)
            auto_detect: Whether to auto-detect if requested driver is not available

        Returns:
            str: The ODBC driver name to use

        """
        if requested_driver is not None:
            if not auto_detect:
                logger.debug(
                    "Using explicitly specified ODBC driver without validation: %s",
                    requested_driver,
                )
                return requested_driver
            # Use the requested driver (validation happens at connection time)
            logger.info("Using requested ODBC driver: %s", requested_driver)
            return requested_driver

        # No driver specified - use default
        logger.info(
            "No ODBC driver specified for PostgreSQL. Using default: %s",
            DEFAULT_POSTGRESQL_DRIVER,
        )
        return DEFAULT_POSTGRESQL_DRIVER

    def _repr_fields(self) -> str:
        """Get string representation of fields (for use in __repr__)."""
        base_repr = super()._repr_fields()
        return f"ssl_mode={self.ssl_mode}, {base_repr}"
