# Path: sygnal/exceptions.py
# class ProxyConnectError(ConnectError):
#     """
#     Exception raised when we are unable to start a connection using a HTTP proxy
#     This indicates an issue with the HTTP Proxy in use rather than the final
#     endpoint we wanted to contact.
#     """
# 
#     pass


import logging
from base64 import urlsafe_b64encode
from typing import Optional, Tuple
from twisted.internet import defer, protocol
from twisted.internet.base import ReactorBase
from twisted.internet.defer import Deferred
from twisted.internet.interfaces import IProtocolFactory, IStreamClientEndpoint
from twisted.internet.protocol import Protocol, connectionDone
from twisted.web import http
from zope.interface import implementer
from sygnal.exceptions import ProxyConnectError

class HTTPConnectSetupClient(http.HTTPClient):
    """HTTPClient protocol to send a CONNECT message for proxies and read the response.

    Args:
        host (bytes): The hostname to send in the CONNECT message
        port (int): The port to send in the CONNECT message
        proxy_auth (tuple): None or tuple of (username, pasword) for HTTP basic proxy
            authentication
    """

    def __init__(self, host: bytes, port: int, proxy_auth: Optional[Tuple[str, str]]):
        self.host = host
        self.port = port
        self._proxy_auth = proxy_auth
        self.on_connected: defer.Deferred = defer.Deferred()

    def connectionMade(self):
        logger.debug("Connected to proxy, sending CONNECT")
        self.sendCommand(b"CONNECT", b"%s:%d" % (self.host, self.port))
        if self._proxy_auth is not None:
            username, password = self._proxy_auth
            # a credential pair is a urlsafe-base64-encoded pair separated by colon
            encoded_credentials = urlsafe_b64encode(f"{username}:{password}".encode())
            self.sendHeader(b"Proxy-Authorization", b"basic " + encoded_credentials)
        self.endHeaders()

    def handleStatus(self, version, status, message):
        logger.debug("Got Status: %s %s %s", status, message, version)
        if status != b"200":

# Path: sygnal/exceptions.py
# class ProxyConnectError(ConnectError):
#     """
#     Exception raised when we are unable to start a connection using a HTTP proxy
#     This indicates an issue with the HTTP Proxy in use rather than the final
#     endpoint we wanted to contact.
#     """
# 
#     pass


# Path: sygnal/helper/proxy/connectproxyclient_twisted.py
import logging
from base64 import urlsafe_b64encode
from typing import Optional, Tuple
from twisted.internet import defer, protocol
from twisted.internet.base import ReactorBase
from twisted.internet.defer import Deferred
from twisted.internet.interfaces import IProtocolFactory, IStreamClientEndpoint
from twisted.internet.protocol import Protocol, connectionDone
from twisted.web import http
from zope.interface import implementer
from sygnal.exceptions import ProxyConnectError


class HTTPConnectSetupClient(http.HTTPClient):
    """HTTPClient protocol to send a CONNECT message for proxies and read the response.

    Args:
        host (bytes): The hostname to send in the CONNECT message
        port (int): The port to send in the CONNECT message
        proxy_auth (tuple): None or tuple of (username, pasword) for HTTP basic proxy
            authentication
    """

    def __init__(self, host: bytes, port: int, proxy_auth: Optional[Tuple[str, str]]):
        self.host = host
        self.port = port
        self._proxy_auth = proxy_auth
        self.on_connected: defer.Deferred = defer.Deferred()

    def connectionMade(self):
        logger.debug("Connected to proxy, sending CONNECT")
        self.sendCommand(b"CONNECT", b"%s:%d" % (self.host, self.port))
        if self._proxy_auth is not None:
            username, password = self._proxy_auth
            # a credential pair is a urlsafe-base64-encoded pair separated by colon
            encoded_credentials = urlsafe_b64encode(f"{username}:{password}".encode())
            self.sendHeader(b"Proxy-Authorization", b"basic " + encoded_credentials)
        self.endHeaders()

    def handleStatus(self, version, status, message):
        logger.debug("Got Status: %s %s %s", status, message, version)
        if status != b"200":

            raise ProxyConnectError("Unexpected status on CONNECT: %s" % status)