import os
from typing import List, Optional, Union

from .postgresql import PostgresClient

DEFAULT_POSTGRES_PREFIX = "PG"
ENV_URL_KEYS = ["DATABASE_URL", "POSTGRES_URL", "PG_URL", "PG_DSN"]

DEFAULT_DORIS_PREFIX = "DORIS"
DORIS_URL_KEYS = ["DORIS_URL", "DORIS_DSN"]

DEFAULT_ES_PREFIX = "ES"
ES_URL_KEYS = ["ELASTICSEARCH_URL", "ES_URL", "ES_HOST"]


def _resolve_url_from_env(prefix: str = DEFAULT_POSTGRES_PREFIX) -> Optional[str]:
    for key in ENV_URL_KEYS:
        value = os.getenv(key)
        if value:
            return value

    user = os.getenv(f"{prefix}_USER")
    password = os.getenv(f"{prefix}_PASSWORD")
    host = os.getenv(f"{prefix}_HOST")
    port = os.getenv(f"{prefix}_PORT")
    database = os.getenv(f"{prefix}_DATABASE") or os.getenv(f"{prefix}_DB")
    driver = os.getenv(f"{prefix}_DRIVER")

    if user and password and host and port and database and driver:
        return f"postgresql+{driver}://{user}:{password}@{host}:{port}/{database}"

    return None


def create_postgres_client(
    url: Optional[str] = None,
    echo: bool = False,
    env_prefix: str = DEFAULT_POSTGRES_PREFIX,
) -> PostgresClient:
    """Create a configured PostgreSQL client.

    The factory first uses an explicit `url` value. If no URL is provided,
    it falls back to environment variables.
    """
    connection_url = url or _resolve_url_from_env(env_prefix)
    if not connection_url:
        raise ValueError(
            "No PostgreSQL URL configured. Provide a `url` or set environment variables: "
            "DATABASE_URL, POSTGRES_URL, PG_URL, or PG_USER/PG_PASSWORD/PG_HOST/PG_PORT/PG_DATABASE."
        )
    return PostgresClient(connection_url, echo=echo)


def get_postgres_client(
    url: Optional[str] = None,
    echo: bool = False,
    env_prefix: str = DEFAULT_POSTGRES_PREFIX,
) -> PostgresClient:
    """Alias for create_postgres_client."""
    return create_postgres_client(url=url, echo=echo, env_prefix=env_prefix)


def _resolve_es_hosts_from_env(prefix: str = DEFAULT_ES_PREFIX) -> Optional[List[str]]:
    for key in ES_URL_KEYS:
        value = os.getenv(key)
        if value:
            return [value]

    host = os.getenv(f"{prefix}_HOST")
    port = os.getenv(f"{prefix}_PORT")
    scheme = os.getenv(f"{prefix}_SCHEME")

    if host and port and scheme:
        return [f"{scheme}://{host}:{port}"]

    return None


def create_elasticsearch_client(
    hosts: Optional[Union[str, List[str]]] = None,
    env_prefix: str = DEFAULT_ES_PREFIX,
    **kwargs,
):
    """Create a configured Elasticsearch client.

    The factory first uses an explicit `hosts` value. If no hosts are provided,
    it falls back to environment variables.
    """
    if hosts is None:
        resolved = _resolve_es_hosts_from_env(env_prefix)
        if not resolved:
            raise ValueError(
                "No Elasticsearch hosts configured. Provide `hosts` or set environment variables: "
                "ELASTICSEARCH_URL, ES_URL, ES_HOST, or ES_HOST/ES_PORT/ES_SCHEME."
            )
        hosts = resolved

    try:
        from .elasticsearch import ElasticsearchClient
    except ImportError as exc:
        raise ImportError(
            "Elasticsearch support is optional. Install with `pip install db_core[elasticsearch]` "
            "or add `elasticsearch[async]` to your environment."
        ) from exc

    return ElasticsearchClient(hosts=hosts, **kwargs)


def get_elasticsearch_client(
    hosts: Optional[Union[str, List[str]]] = None,
    env_prefix: str = DEFAULT_ES_PREFIX,
    **kwargs,
):
    """Alias for create_elasticsearch_client."""
    return create_elasticsearch_client(hosts=hosts, env_prefix=env_prefix, **kwargs)


def _resolve_doris_url_from_env(prefix: str = DEFAULT_DORIS_PREFIX) -> Optional[str]:
    for key in DORIS_URL_KEYS:
        value = os.getenv(key)
        if value:
            return value

    user = os.getenv(f"{prefix}_USER")
    password = os.getenv(f"{prefix}_PASSWORD")
    host = os.getenv(f"{prefix}_HOST")
    port = os.getenv(f"{prefix}_PORT")
    database = os.getenv(f"{prefix}_DATABASE") or os.getenv(f"{prefix}_DB")
    driver = os.getenv(f"{prefix}_DRIVER")

    if host and port and database and driver:
        url = f"mysql+{driver}://{user}"
        if password:
            url += f":{password}"
        url += f"@{host}:{port}/{database}"
        return url

    return None


def create_doris_client(
    url: Optional[str] = None,
    echo: bool = False,
    env_prefix: str = DEFAULT_DORIS_PREFIX,
):
    """Create a configured Apache Doris client.

    The factory first uses an explicit `url` value. If no URL is provided,
    it falls back to environment variables.
    """
    try:
        from .doris import DorisClient
    except ImportError as exc:
        raise ImportError(
            "Doris support is optional. Install with `pip install db_core[doris]` "
            "or add `aiomysql` to your environment."
        ) from exc

    connection_url = url or _resolve_doris_url_from_env(env_prefix)
    if not connection_url:
        raise ValueError(
            "No Apache Doris URL configured. Provide a `url` or set environment variables: "
            "DORIS_URL, DORIS_DSN, or DORIS_USER/DORIS_PASSWORD/DORIS_HOST/DORIS_PORT/DORIS_DATABASE."
        )
    return DorisClient(connection_url, echo=echo)


def get_doris_client(
    url: Optional[str] = None,
    echo: bool = False,
    env_prefix: str = DEFAULT_DORIS_PREFIX,
):
    """Alias for create_doris_client."""
    return create_doris_client(url=url, echo=echo, env_prefix=env_prefix)
