import logging
from urllib.parse import urlparse

from urllib3 import HTTPConnectionPool, HTTPSConnectionPool, PoolManager
from urllib3.connection import HTTPConnection, HTTPSConnection

from .constants import HTTP_PROXY_SOCK_RDNS_SCHEMAS

logger = logging.getLogger('netbox.utilities')


class ProxyHTTPConnection(HTTPConnection):
    """
    A Proxy connection class that uses a SOCK proxy - used to create
    a urllib3 PoolManager that routes connections via the proxy.
    This is for an HTTP (not HTTPS) connection
    """
    use_rdns = False

    def __init__(self, *args, **kwargs):
        socks_options = kwargs.pop('_socks_options')
        self._proxy_url = socks_options['proxy_url']
        super().__init__(*args, **kwargs)

    def _new_conn(self):
        try:
            from python_socks.sync import Proxy
        except ModuleNotFoundError as e:
            logger.info(
                "Configuring an HTTP proxy using SOCKS requires the python_socks library. Check that it has been "
                "installed."
            )
            raise e

        proxy = Proxy.from_url(self._proxy_url, rdns=self.use_rdns)
        return proxy.connect(
            dest_host=self.host,
            dest_port=self.port,
            timeout=self.timeout
        )


class ProxyHTTPSConnection(ProxyHTTPConnection, HTTPSConnection):
    """
    A Proxy connection class for an HTTPS (not HTTP) connection.
    """
    pass


class RdnsProxyHTTPConnection(ProxyHTTPConnection):
    """
    A Proxy connection class for an HTTP remote-dns connection.
    I.E. socks4a, socks4h, socks5a, socks5h
    """
    use_rdns = True


class RdnsProxyHTTPSConnection(ProxyHTTPSConnection):
    """
    A Proxy connection class for an HTTPS remote-dns connection.
    I.E. socks4a, socks4h, socks5a, socks5h
    """
    use_rdns = True


class ProxyHTTPConnectionPool(HTTPConnectionPool):
    ConnectionCls = ProxyHTTPConnection


class ProxyHTTPSConnectionPool(HTTPSConnectionPool):
    ConnectionCls = ProxyHTTPSConnection


class RdnsProxyHTTPConnectionPool(HTTPConnectionPool):
    ConnectionCls = RdnsProxyHTTPConnection


class RdnsProxyHTTPSConnectionPool(HTTPSConnectionPool):
    ConnectionCls = RdnsProxyHTTPSConnection


class ProxyPoolManager(PoolManager):
    def __init__(self, proxy_url, timeout=5, num_pools=10, headers=None, **connection_pool_kw):
        # python_socks uses rdns param to denote remote DNS parsing and
        # doesn't accept the 'h' or 'a' in the proxy URL
        if use_rdns := urlparse(proxy_url).scheme in HTTP_PROXY_SOCK_RDNS_SCHEMAS:
            proxy_url = proxy_url.replace('socks5h:', 'socks5:').replace('socks5a:', 'socks5:')
            proxy_url = proxy_url.replace('socks4h:', 'socks4:').replace('socks4a:', 'socks4:')

        connection_pool_kw['_socks_options'] = {'proxy_url': proxy_url}
        connection_pool_kw['timeout'] = timeout

        super().__init__(num_pools, headers, **connection_pool_kw)

        if use_rdns:
            self.pool_classes_by_scheme = {
                'http': RdnsProxyHTTPConnectionPool,
                'https': RdnsProxyHTTPSConnectionPool,
            }
        else:
            self.pool_classes_by_scheme = {
                'http': ProxyHTTPConnectionPool,
                'https': ProxyHTTPSConnectionPool,
            }
