"""
配置加载：连接映射（单连接 / 多 Profile）、安全与行为配置。
"""
from __future__ import annotations

import os
import sys
import json
from dataclasses import dataclass, field


@dataclass
class ConnectionConfig:
    """单条连接配置"""
    host: str
    port: int
    user: str
    password: str
    database: str | None = None
    charset: str = "utf8mb4"
    description: str | None = None  # 可选说明/别名，供智能体根据用户自然语言匹配
    databases: list[str] | None = None  # 可选：该连接聚焦的数据库列表，设则 list_databases 只返回这些，list_tables/describe_table 仅允许访问这些库


@dataclass
class SafetyConfig:
    """安全与行为配置（全局）"""
    read_only: bool = False
    max_select_rows: int = 10000
    confirm_affected_above: int = 0
    auto_confirm_affected_below: int = 0
    query_timeout_seconds: int = 30
    slow_query_seconds: int = 10


def _parse_bool(val: str | None) -> bool:
    if val is None:
        return False
    return str(val).strip().lower() in ("1", "true", "yes", "on")


def _parse_int(val: str | int | None, default: int) -> int:
    if val is None:
        return default
    if isinstance(val, int):
        return val
    try:
        return int((val or "").strip())
    except (ValueError, AttributeError):
        return default


def load_safety_config() -> SafetyConfig:
    """从环境变量加载安全配置"""
    return SafetyConfig(
        read_only=_parse_bool(os.environ.get("DB_READ_ONLY")),
        max_select_rows=_parse_int(os.environ.get("DB_MAX_SELECT_ROWS"), 10000),
        confirm_affected_above=_parse_int(os.environ.get("DB_CONFIRM_AFFECTED_ABOVE"), 0),
        auto_confirm_affected_below=_parse_int(os.environ.get("DB_AUTO_CONFIRM_AFFECTED_BELOW"), 0),
        query_timeout_seconds=_parse_int(os.environ.get("DB_QUERY_TIMEOUT_SECONDS"), 30),
        slow_query_seconds=_parse_int(os.environ.get("DB_SLOW_QUERY_SECONDS"), 10),
    )


def load_connection_map() -> tuple[ConnectionConfig, dict[str, ConnectionConfig], str]:
    """
    加载连接配置。
    返回: (default_connection, connection_map, default_profile_name)
    - 若设置了 DB_PROFILES 且解析成功：仅用 DB_PROFILES，不需 DB_HOST/USER/PASSWORD；default 取 profile 中 "default" 或第一个。
    - 否则：需要 DB_HOST, DB_USER, DB_PASSWORD，并可选 DB_PROFILES 或 DB_<PROFILE>_*。
    """
    connection_map: dict[str, ConnectionConfig] = {}
    default_profile_name = "default"
    default: ConnectionConfig | None = None

    # 优先: 按环境的数组 TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES（推荐，仅用此方式）
    for env in ("test", "uat", "prod"):
        key = f"{env.upper()}_DB_PROFILES"
        arr_json = os.environ.get(key)
        if not arr_json:
            continue
        try:
            arr = json.loads(arr_json)
            if not isinstance(arr, list):
                continue
            for i, v in enumerate(arr):
                if not isinstance(v, dict):
                    continue
                h = str(v.get("host", "")).strip()
                u = str(v.get("user", "")).strip()
                p = str(v.get("password", ""))
                if not h or not u:
                    continue
                port = _parse_int(v.get("port"), 3306)
                db_val = v.get("database")
                database = (str(db_val).strip() or None) if db_val is not None else None
                desc = v.get("description")
                description = (str(desc).strip() or None) if desc is not None else None
                dbs_val = v.get("databases")
                if dbs_val is None:
                    databases = None
                elif isinstance(dbs_val, list):
                    databases = [str(x).strip() for x in dbs_val if x]
                else:
                    databases = [x.strip() for x in str(dbs_val).split(",") if x.strip()]
                sub_name = (v.get("name") or "").strip() or str(i)
                profile_key = f"{env}_{sub_name}" if sub_name != str(i) else f"{env}_{i}"
                connection_map[profile_key] = ConnectionConfig(
                    host=h,
                    port=port,
                    user=u,
                    password=p,
                    database=database,
                    charset=str(v.get("charset", "utf8mb4")).strip() or "utf8mb4",
                    description=description,
                    databases=databases,
                )
        except json.JSONDecodeError:
            pass

    if connection_map:
        prod_keys = [k for k in connection_map if k.startswith("prod_")]
        if prod_keys:
            default_profile_name = prod_keys[0]
            default = connection_map[default_profile_name]
        else:
            default_profile_name = next(iter(connection_map))
            default = connection_map[default_profile_name]
        return default, connection_map, default_profile_name

    # 备选: 单 JSON DB_PROFILES（不推荐，请用 *_DB_PROFILES）
    profiles_json = os.environ.get("DB_PROFILES")
    if profiles_json:
        try:
            data = json.loads(profiles_json)
            if isinstance(data, dict):
                for k, v in data.items():
                    if isinstance(v, dict):
                        h = str(v.get("host", "")).strip()
                        u = str(v.get("user", "")).strip()
                        p = str(v.get("password", ""))
                        if not h or not u:
                            continue
                        port = _parse_int(v.get("port"), 3306)
                        db_val = v.get("database")
                        database = (str(db_val).strip() or None) if db_val is not None else None
                        desc = v.get("description")
                        description = (str(desc).strip() or None) if desc is not None else None
                        dbs_val = v.get("databases")
                        if dbs_val is None:
                            databases = None
                        elif isinstance(dbs_val, list):
                            databases = [str(x).strip() for x in dbs_val if x]
                        else:
                            databases = [x.strip() for x in str(dbs_val).split(",") if x.strip()]
                        connection_map[k] = ConnectionConfig(
                            host=h,
                            port=port,
                            user=u,
                            password=p,
                            database=database,
                            charset=str(v.get("charset", "utf8mb4")).strip() or "utf8mb4",
                            description=description,
                            databases=databases,
                        )
                if connection_map:
                    default_profile_name = "default" if "default" in connection_map else next(iter(connection_map))
                    if "default" not in connection_map and default_profile_name != "default":
                        connection_map["default"] = connection_map[default_profile_name]
                    default = connection_map[default_profile_name]
        except json.JSONDecodeError:
            print("警告: DB_PROFILES JSON 解析失败，将使用 DB_HOST/USER/PASSWORD", file=sys.stderr)

    if default is not None:
        return default, connection_map, default_profile_name

    # 未设置 *_DB_PROFILES 与 DB_PROFILES：使用单连接 env
    host = os.environ.get("DB_HOST", "").strip()
    user = os.environ.get("DB_USER", "").strip()
    password = os.environ.get("DB_PASSWORD", "")
    port = _parse_int(os.environ.get("DB_PORT"), 3306)
    database = (os.environ.get("DB_DATABASE") or "").strip() or None
    charset = (os.environ.get("DB_CHARSET") or "utf8mb4").strip() or "utf8mb4"

    if not host or not user:
        print("错误: 缺少必要的环境变量。多环境请配置 TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES；单环境请配置 DB_HOST, DB_USER, DB_PASSWORD", file=sys.stderr)
        sys.exit(1)

    default = ConnectionConfig(
        host=host,
        port=port,
        user=user,
        password=password,
        database=database,
        charset=charset,
    )

    if not connection_map:
        # 备选: 默认连接登记为 prod，并扫描 DB_<PROFILE>_*
        connection_map["prod"] = default
        default_profile_name = "prod"
        for profile in ("dev", "test", "uat", "prod"):
            ph = os.environ.get(f"DB_{profile.upper()}_HOST", "").strip()
            pu = os.environ.get(f"DB_{profile.upper()}_USER", "").strip()
            pp = os.environ.get(f"DB_{profile.upper()}_PASSWORD", "")
            if ph and pu:
                desc = (os.environ.get(f"DB_{profile.upper()}_DESCRIPTION", "") or "").strip() or None
                dbs_key = f"DB_{profile.upper()}_DATABASES"
                if dbs_key not in os.environ:
                    databases = None  # 未配置：默认所有库
                else:
                    dbs_env = (os.environ.get(dbs_key) or "").strip()
                    databases = [x.strip() for x in dbs_env.split(",") if x.strip()]  # 空串得 []：不允许任何库
                connection_map[profile] = ConnectionConfig(
                    host=ph,
                    port=_parse_int(os.environ.get(f"DB_{profile.upper()}_PORT"), 3306),
                    user=pu,
                    password=pp,
                    database=(os.environ.get(f"DB_{profile.upper()}_DATABASE", "").strip() or None),
                    charset=charset,
                    description=desc,
                    databases=databases,
                )
        if "prod" not in connection_map:
            connection_map["prod"] = default

    return default, connection_map, default_profile_name
