import logging
import os
import unittest
from unittest import mock

from xsdk.mysql_client import DBError, MySQLClient, MySQLConfig


class MySQLClientEnvTestCase(unittest.TestCase):
    def test_mysql_config_parses_env_value_with_default_timeout(self) -> None:
        config = MySQLConfig.parse_env_value("127.0.0.1:3306:root:pwd")

        self.assertEqual(config.host, "127.0.0.1")
        self.assertEqual(config.port, 3306)
        self.assertEqual(config.user, "root")
        self.assertEqual(config.password, "pwd")
        self.assertEqual(config.timeout, 6000)
        self.assertEqual(config.charset, "utf8")

    def test_mysql_config_parses_env_value_with_explicit_timeout(self) -> None:
        config = MySQLConfig.parse_env_value("db.example.com:3307:app:pwd:9000", charset="utf8mb4")

        self.assertEqual(config.host, "db.example.com")
        self.assertEqual(config.port, 3307)
        self.assertEqual(config.user, "app")
        self.assertEqual(config.password, "pwd")
        self.assertEqual(config.timeout, 9000)
        self.assertEqual(config.charset, "utf8mb4")

    def test_mysql_config_parses_env_value_with_colon_in_password(self) -> None:
        config = MySQLConfig.parse_env_value("127.0.0.1:3306:root:pwd:with:colon:7000")

        self.assertEqual(config.password, "pwd:with:colon")
        self.assertEqual(config.timeout, 7000)

    def test_mysql_config_raises_for_invalid_env_value(self) -> None:
        with self.assertRaises(DBError):
            MySQLConfig.parse_env_value("127.0.0.1:3306:root")

    def test_mysql_config_reads_from_env_name(self) -> None:
        with mock.patch.dict(
            os.environ,
            {"XENV_DB_MAIN": "127.0.0.1:3306:root:pwd:6500"},
            clear=True,
        ):
            config = MySQLConfig.get_env_config("XENV_DB_MAIN")

        self.assertEqual(config.host, "127.0.0.1")
        self.assertEqual(config.port, 3306)
        self.assertEqual(config.user, "root")
        self.assertEqual(config.password, "pwd")
        self.assertEqual(config.timeout, 6500)

    def test_mysql_client_get_instance_supports_env_name(self) -> None:
        custom_logger = logging.getLogger("mysql-test")
        with mock.patch.dict(
            os.environ,
            {"XENV_DB_MAIN": "127.0.0.1:3306:root:pwd:6500"},
            clear=True,
        ):
            with mock.patch.object(MySQLClient, "__init__", return_value=None) as mock_init:
                client = MySQLClient.get_instance(env_name="XENV_DB_MAIN", logger=custom_logger)

        self.assertIsInstance(client, MySQLClient)
        args = mock_init.call_args.args
        self.assertIsInstance(args[0], MySQLConfig)
        self.assertEqual(args[0].host, "127.0.0.1")
        self.assertEqual(args[0].timeout, 6500)
        self.assertIs(args[1], custom_logger)

    def test_mysql_client_get_instance_rejects_multiple_sources(self) -> None:
        with self.assertRaises(TypeError):
            MySQLClient.get_instance("conf/mysql.ini", env_name="XENV_DB_MAIN")

    def test_mysql_client_init_passes_connect_timeout_to_pool(self) -> None:
        config = MySQLConfig(timeout=6000)
        with mock.patch("xsdk.mysql_client.PooledDB", return_value=object()) as mock_pool:
            MySQLClient(config)

        self.assertEqual(mock_pool.call_args.kwargs["connect_timeout"], 6.0)


if __name__ == "__main__":
    unittest.main()
