"""基础测试：配置与 SQL 解析，不依赖真实数据库。"""
import os
import pytest


def test_sql_split_and_classify():
    from mysql_mcp.sql_analysis import split_sql, analyze_one, ensure_single_statement, classify_statement

    # 单条
    assert split_sql("SELECT 1") == ["SELECT 1"]
    assert classify_statement("SELECT 1") == ("SELECT", "SELECT")
    assert classify_statement("CREATE TABLE t (id int)") == ("DDL", "CREATE")
    assert classify_statement("UPDATE t SET x=1") == ("UPDATE", "UPDATE")
    assert classify_statement("DELETE FROM t") == ("DELETE", "DELETE")
    assert classify_statement("INSERT INTO t VALUES (1)") == ("INSERT", "INSERT")

    # 多条
    two = split_sql("SELECT 1; SELECT 2")
    assert len(two) == 2
    assert "SELECT 1" in two[0]
    assert "SELECT 2" in two[1]

    # ensure_single 多条则报错
    with pytest.raises(ValueError, match="仅支持单条"):
        ensure_single_statement("SELECT 1; SELECT 2")
    assert ensure_single_statement("SELECT 1") == "SELECT 1"

    # analyze_one
    a = analyze_one("CREATE TABLE t (id int)")
    assert a.stype == "DDL"
    assert "手动执行" in a.message


def test_config_load_default(monkeypatch):
    """无 DB_PROFILES 时使用 DB_HOST/USER/PASSWORD 并登记 prod"""
    monkeypatch.setenv("DB_HOST", "localhost")
    monkeypatch.setenv("DB_USER", "u")
    monkeypatch.setenv("DB_PASSWORD", "p")
    from mysql_mcp.config import load_connection_map

    default, cmap, name = load_connection_map()
    assert default.host == "localhost"
    assert default.port == 3306
    assert "prod" in cmap
    assert name == "prod"


def test_config_profiles_json(monkeypatch):
    """仅 DB_PROFILES 时不需要 DB_HOST/USER/PASSWORD，default 来自 profile，port 必填"""
    monkeypatch.setenv(
        "DB_PROFILES",
        '{"dev":{"host":"d","port":3306,"user":"du","password":"dp","database":"db"},"default":{"host":"d","port":3306,"user":"du","password":"dp"}}',
    )
    from mysql_mcp.config import load_connection_map

    default, cmap, name = load_connection_map()
    assert "dev" in cmap
    assert cmap["dev"].host == "d"
    assert cmap["dev"].port == 3306
    assert default.host == "d"  # 仅 DB_PROFILES 时 default 来自 profile
    assert name in ("default", "dev")


def test_env_array_takes_precedence_over_db_profiles(monkeypatch):
    """方式二优先：当同时设置 *_DB_PROFILES 与 DB_PROFILES 时，仅用 *_DB_PROFILES"""
    monkeypatch.setenv("PROD_DB_PROFILES", '[{"host":"from_array","port":3306,"user":"u","password":"p"}]')
    monkeypatch.setenv(
        "DB_PROFILES",
        '{"prod":{"host":"from_single_json","port":3306,"user":"u","password":"p"}}',
    )
    from mysql_mcp.config import load_connection_map

    default, cmap, name = load_connection_map()
    assert name == "prod_0"
    assert default.host == "from_array"
    assert "prod_0" in cmap
    assert cmap["prod_0"].host == "from_array"


def test_env_array_profiles(monkeypatch):
    """TEST_DB_PROFILES / UAT_DB_PROFILES / PROD_DB_PROFILES 数组形式，每环境多个连接"""
    monkeypatch.setenv(
        "TEST_DB_PROFILES",
        '[{"host":"t1","port":3306,"user":"u1","password":"p1","database":"d1"},{"host":"t2","port":3306,"user":"u2","password":"p2","name":"finance"}]',
    )
    monkeypatch.setenv(
        "PROD_DB_PROFILES",
        '[{"host":"p1","port":3306,"user":"pu","password":"pp","database":"app"}]',
    )
    from mysql_mcp.config import load_connection_map

    default, cmap, name = load_connection_map()
    assert "test_0" in cmap
    assert cmap["test_0"].host == "t1"
    assert "test_finance" in cmap
    assert cmap["test_finance"].host == "t2"
    assert "prod_0" in cmap
    assert cmap["prod_0"].host == "p1"
    assert name == "prod_0"
    assert default.host == "p1"


def test_get_connection_config():
    from mysql_mcp.config import ConnectionConfig, load_safety_config
    from mysql_mcp.client import get_connection_config

    default = ConnectionConfig("h", 3306, "u", "p", None)
    cmap = {"prod": default, "dev": ConnectionConfig("d", 3306, "du", "dp", None)}
    assert get_connection_config(None, default, cmap).host == "h"
    assert get_connection_config("prod", default, cmap).host == "h"
    assert get_connection_config("dev", default, cmap).host == "d"
    with pytest.raises(ValueError, match="未知"):
        get_connection_config("unknown", default, cmap)


def test_safety_config_defaults(monkeypatch):
    """未设置安全相关 env 时使用默认值"""
    for key in ("DB_READ_ONLY", "DB_MAX_SELECT_ROWS", "DB_QUERY_TIMEOUT_SECONDS", "DB_SLOW_QUERY_SECONDS",
                "DB_CONFIRM_AFFECTED_ABOVE", "DB_AUTO_CONFIRM_AFFECTED_BELOW"):
        monkeypatch.delenv(key, raising=False)
    from mysql_mcp.config import load_safety_config
    s = load_safety_config()
    assert s.read_only is False
    assert s.max_select_rows == 10000
    assert s.query_timeout_seconds == 30
    assert s.slow_query_seconds == 10
    assert s.confirm_affected_above == 0
    assert s.auto_confirm_affected_below == 0


def test_safety_config_from_env(monkeypatch):
    """安全配置从环境变量读取"""
    monkeypatch.setenv("DB_READ_ONLY", "true")
    monkeypatch.setenv("DB_MAX_SELECT_ROWS", "5000")
    monkeypatch.setenv("DB_QUERY_TIMEOUT_SECONDS", "60")
    from mysql_mcp.config import load_safety_config
    s = load_safety_config()
    assert s.read_only is True
    assert s.max_select_rows == 5000
    assert s.query_timeout_seconds == 60


def test_sql_analysis_edge_cases():
    """SQL 解析边界：空、空白、单条带注释、写操作需 confirm、多条 ensure 报错"""
    from mysql_mcp.sql_analysis import split_sql, classify_statement, ensure_single_statement, analyze_one
    # 空或空白
    assert split_sql("") == []
    assert split_sql("   \n\t  ") == []
    # INSERT/DELETE 需 confirm
    ai = analyze_one("INSERT INTO t (a) VALUES (1)")
    assert ai.stype == "INSERT"
    assert ai.need_confirm is True
    ad = analyze_one("DELETE FROM t WHERE id=1")
    assert ad.stype == "DELETE"
    assert ad.need_confirm is True
    # 多条 ensure 报错
    with pytest.raises(ValueError, match="仅支持单条"):
        ensure_single_statement("SELECT 1; INSERT INTO t VALUES (1)")
