from __future__ import annotations

import sys
import unittest
from pathlib import Path
from types import ModuleType, SimpleNamespace
from unittest.mock import patch

ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path:
    sys.path.insert(0, str(SRC))

from brightree.exceptions import BrightreeException
from brightree.soap import ZeepSoapClient


class FakeSession:
    def __init__(self) -> None:
        self.auth = None


class FakeClient:
    last_instance = None

    def __init__(self, wsdl, transport) -> None:
        self.wsdl_url = wsdl
        self.transport = transport
        self.wsdl = SimpleNamespace(
            bindings={
                "{http://www.brightree.com/external/PatientService}BasicHttpBinding_IPatientService": object()
            }
        )
        self.created = None
        FakeClient.last_instance = self

    def create_service(self, binding_name, location):
        self.created = {"binding_name": binding_name, "location": location}
        return SimpleNamespace()


class SoapClientTest(unittest.TestCase):
    def test_selects_first_binding_from_wsdl(self) -> None:
        zeep_module = ModuleType("zeep")
        zeep_module.Client = FakeClient

        zeep_transports_module = ModuleType("zeep.transports")
        zeep_transports_module.Transport = lambda session: {"session": session}

        requests_module = ModuleType("requests")
        requests_module.Session = FakeSession

        requests_auth_module = ModuleType("requests.auth")
        requests_auth_module.HTTPBasicAuth = lambda username, password: (username, password)

        with patch.dict(
            sys.modules,
            {
                "zeep": zeep_module,
                "zeep.transports": zeep_transports_module,
                "requests": requests_module,
                "requests.auth": requests_auth_module,
            },
        ):
            ZeepSoapClient(
                wsdl="https://example.com/patient?singleWsdl",
                username="user",
                password="pass",
                location="https://example.com/patient",
            )

        self.assertEqual(
            FakeClient.last_instance.created,
            {
                "binding_name": "{http://www.brightree.com/external/PatientService}BasicHttpBinding_IPatientService",
                "location": "https://example.com/patient",
            },
        )

    def test_raises_when_wsdl_has_no_bindings(self) -> None:
        client = SimpleNamespace(wsdl=SimpleNamespace(bindings={}))
        with self.assertRaises(BrightreeException) as ctx:
            ZeepSoapClient._resolve_binding_name(client)
        self.assertEqual(str(ctx.exception), "No SOAP bindings were found in the WSDL.")


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