# Licensed under a 3-clause BSD style license - see LICENSE.rst


from urllib.parse import parse_qs
from urllib.request import urlopen

from astropy.utils.data import get_pkg_data_contents

from .standard_profile import SAMPSimpleXMLRPCRequestHandler, ThreadingXMLRPCServer

__all__ = []

CROSS_DOMAIN = get_pkg_data_contents("data/crossdomain.xml")
CLIENT_ACCESS_POLICY = get_pkg_data_contents("data/clientaccesspolicy.xml")


class WebProfileRequestHandler(SAMPSimpleXMLRPCRequestHandler):
    """
    Handler of XMLRPC requests performed through the Web Profile.
    """

    def _send_CORS_header(self):
        if self.headers.get("Origin") is not None:
            method = self.headers.get("Access-Control-Request-Method")
            if method and self.command == "OPTIONS":
                # Preflight method
                self.send_header("Content-Length", "0")
                self.send_header(
                    "Access-Control-Allow-Origin", self.headers.get("Origin")
                )
                self.send_header("Access-Control-Allow-Methods", method)
                self.send_header("Access-Control-Allow-Headers", "Content-Type")
                self.send_header("Access-Control-Allow-Credentials", "true")
                if self.headers.get("Access-Control-Request-Private-Network") == "true":
                    self.send_header("Access-Control-Allow-Private-Network", "true")
            else:
                # Simple method
                self.send_header(
                    "Access-Control-Allow-Origin", self.headers.get("Origin")
                )
                self.send_header("Access-Control-Allow-Headers", "Content-Type")
                self.send_header("Access-Control-Allow-Credentials", "true")

    def end_headers(self):
        self._send_CORS_header()
        SAMPSimpleXMLRPCRequestHandler.end_headers(self)

    def _serve_cross_domain_xml(self):
        cross_domain = False

        if self.path == "/crossdomain.xml":
            # Adobe standard
            response = CROSS_DOMAIN

            self.send_response(200, "OK")
            self.send_header("Content-Type", "text/x-cross-domain-policy")
            self.send_header("Content-Length", f"{len(response)}")
            self.end_headers()
            self.wfile.write(response.encode("utf-8"))
            self.wfile.flush()
            cross_domain = True

        elif self.path == "/clientaccesspolicy.xml":
            # Microsoft standard
            response = CLIENT_ACCESS_POLICY

            self.send_response(200, "OK")
            self.send_header("Content-Type", "text/xml")
            self.send_header("Content-Length", f"{len(response)}")
            self.end_headers()
            self.wfile.write(response.encode("utf-8"))
            self.wfile.flush()
            cross_domain = True

        return cross_domain

    def do_POST(self):
        if self._serve_cross_domain_xml():
            return

        return SAMPSimpleXMLRPCRequestHandler.do_POST(self)

    def do_HEAD(self):
        if not self.is_http_path_valid():
            self.report_404()
            return

        if self._serve_cross_domain_xml():
            return

    def do_OPTIONS(self):
        self.send_response(200, "OK")
        self.end_headers()

    def do_GET(self):
        if not self.is_http_path_valid():
            self.report_404()
            return

        split_path = self.path.split("?")

        if split_path[0] in [f"/translator/{clid}" for clid in self.server.clients]:
            # Request of a file proxying
            urlpath = parse_qs(split_path[1])
            try:
                proxyfile = urlopen(urlpath["ref"][0])
                self.send_response(200, "OK")
                self.end_headers()
                self.wfile.write(proxyfile.read())
                proxyfile.close()
            except OSError:
                self.report_404()
                return

        if self._serve_cross_domain_xml():
            return

    def is_http_path_valid(self):
        valid_paths = ["/clientaccesspolicy.xml", "/crossdomain.xml"] + [
            f"/translator/{clid}" for clid in self.server.clients
        ]
        return self.path.split("?")[0] in valid_paths


class WebProfileXMLRPCServer(ThreadingXMLRPCServer):
    """
    XMLRPC server supporting the SAMP Web Profile.
    """

    def __init__(
        self,
        addr,
        log=None,
        requestHandler=WebProfileRequestHandler,
        logRequests=True,
        allow_none=True,
        encoding=None,
    ):
        self.clients = []
        ThreadingXMLRPCServer.__init__(
            self, addr, log, requestHandler, logRequests, allow_none, encoding
        )

    def add_client(self, client_id):
        self.clients.append(client_id)

    def remove_client(self, client_id):
        try:
            self.clients.remove(client_id)
        except ValueError:
            # No warning here because this method gets called for all clients,
            # not just web clients, and we expect it to fail for non-web
            # clients.
            pass


def web_profile_text_dialog(request, queue):
    samp_name = "unknown"

    if isinstance(request[0], str):
        # To support the old protocol version
        samp_name = request[0]
    else:
        samp_name = request[0]["samp.name"]

    text = f"""A Web application which declares to be

Name: {samp_name}
Origin: {request[2]}

is requesting to be registered with the SAMP Hub.
Pay attention that if you permit its registration, such
application will acquire all current user privileges, like
file read/write.

Do you give your consent? [yes|no]"""

    print(text)
    answer = input(">>> ")
    queue.put(answer.lower() in ["yes", "y"])
