import ssl
import socket
import logging
from requests.adapters import HTTPAdapter

logger = logging.getLogger("nebulascrape.transport.http1")


class TLSFingerprintAdapter(HTTPAdapter):
    def __init__(self, profile_data: dict, *args, **kwargs):
        self._profile = profile_data
        self._ssl_context = None
        self._source_address = kwargs.pop("source_address", None)
        self._server_hostname = kwargs.pop("server_hostname", None)
        self._build_ssl_context()
        super().__init__(*args, **kwargs)

    def _build_ssl_context(self):
        ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
        ctx.minimum_version = self._profile.get("tls_min", ssl.TLSVersion.TLSv1_2)
        ctx.maximum_version = self._profile.get("tls_max", ssl.TLSVersion.TLSv1_3)

        cipher_list = self._profile.get("cipher_suite", [])
        if cipher_list:
            try:
                ctx.set_ciphers(":".join(cipher_list))
            except ssl.SSLError:
                pass

        ecdh = self._profile.get("ecdh_curve", "prime256v1")
        try:
            ctx.set_ecdh_curve(ecdh)
        except Exception:
            pass

        if self._server_hostname:
            ctx.server_hostname = self._server_hostname
            ctx.check_hostname = False

        ctx.orig_wrap_socket = ctx.wrap_socket
        ctx.wrap_socket = self._wrap_socket_override(ctx)
        self._ssl_context = ctx

    def _wrap_socket_override(self, ctx):
        server_hostname = self._server_hostname

        def wrap_socket(*args, **kwargs):
            if server_hostname:
                kwargs["server_hostname"] = server_hostname
                ctx.check_hostname = False
            else:
                ctx.check_hostname = True
            return ctx.orig_wrap_socket(*args, **kwargs)

        return wrap_socket

    def init_poolmanager(self, *args, **kwargs):
        kwargs["ssl_context"] = self._ssl_context
        if self._source_address:
            kwargs["source_address"] = self._source_address
        return super().init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        kwargs["ssl_context"] = self._ssl_context
        if self._source_address:
            kwargs["source_address"] = self._source_address
        return super().proxy_manager_for(*args, **kwargs)


class TransportHTTP:
    name = "http1"

    def __init__(self, profile_data: dict, **kwargs):
        self.profile_data = profile_data
        self.kwargs = kwargs
        self.adapter = TLSFingerprintAdapter(profile_data, **kwargs)

    def mount_on(self, session):
        session.mount("https://", self.adapter)
        session.mount("http://", HTTPAdapter())

    def rebuild(self, session):
        self.adapter = TLSFingerprintAdapter(self.profile_data, **self.kwargs)
        self.mount_on(session)
