"""A task-owned HTTP server for real nginx protocol and streaming checks."""
import base64
import hashlib
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import json
import subprocess
import threading

LEGACY_VHOST = """server {
    listen 80;
    server_name legacy.example;
    location / {
        proxy_pass http://127.0.0.1:31000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 120s;
    }
}
"""


class BackendServer(ThreadingHTTPServer):
    def __init__(self):
        super().__init__(("127.0.0.1", 0), Backend)
        self.stream_release = threading.Event()
        self.stream_finished = threading.Event()


class Backend(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def do_GET(self):
        if self.path == "/ws":
            return self.websocket()
        if self.path == "/stream":
            return self.stream()
        payload = json.dumps({"build_sha": "a" * 40, "path": self.path,
                              "upgrade": self.headers.get("Upgrade"),
                              "connection": self.headers.get("Connection"),
                              "ingress_received": "X-App-Robot-Backend-Token" in self.headers}).encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(payload)))
        self.end_headers()
        self.wfile.write(payload)

    def websocket(self):
        self.close_connection = True
        if (self.headers.get("Upgrade", "").lower() != "websocket"
                or self.headers.get("Connection", "").lower() != "upgrade"
                or self.request_version != "HTTP/1.1"
                or "X-App-Robot-Backend-Token" in self.headers):
            self.send_error(400)
            return
        key = self.headers["Sec-WebSocket-Key"] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
        self.send_response(101)
        self.send_header("Upgrade", "websocket")
        self.send_header("Connection", "Upgrade")
        self.send_header("Sec-WebSocket-Accept", base64.b64encode(hashlib.sha1(key.encode()).digest()).decode())
        self.end_headers()
        self.connection.settimeout(2)
        frame = self.rfile.read(2)
        if len(frame) != 2 or frame[0] != 0x81 or frame[1] & 0x80 == 0 or frame[1] & 0x7F > 125:
            return
        mask = self.rfile.read(4)
        payload = self.rfile.read(frame[1] & 0x7F)
        decoded = bytes(value ^ mask[index % 4] for index, value in enumerate(payload))
        self.wfile.write(bytes((0x81, len(decoded))) + decoded)
        self.wfile.flush()

    def stream(self):
        self.close_connection = True
        self.send_response(200)
        self.send_header("Content-Type", "text/event-stream")
        self.end_headers()
        self.wfile.write(b"data: first\n\n")
        self.wfile.flush()
        try:
            if self.server.stream_release.wait(5):
                self.wfile.write(b"data: second\n\n")
                self.wfile.flush()
        finally:
            self.server.stream_finished.set()

    def log_message(self, *_args):
        pass


def stop(process):
    process.terminate()
    try:
        process.communicate(timeout=5)
    except subprocess.TimeoutExpired:
        process.kill()
        process.communicate(timeout=5)
