#!/usr/bin/env python3

import os
from email.utils import formatdate
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import urlsplit


ROOT = Path("/home/ubuntu/cobbleverse/resource-pack-host")
DOWNLOAD_PATHS = {"/download/kerncobble", "/download/kerncobble/"}
DOWNLOAD_FILE = ROOT / "Kern-Launcher-Setup-1.0.3.exe"
DOWNLOAD_NAME = "Kern-Launcher-Setup-1.0.3.exe"


class DownloadHandler(SimpleHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def do_HEAD(self):
        if urlsplit(self.path).path in DOWNLOAD_PATHS:
            self._send_download(send_body=False)
            return
        super().do_HEAD()

    def do_GET(self):
        if urlsplit(self.path).path in DOWNLOAD_PATHS:
            self._send_download(send_body=True)
            return
        super().do_GET()

    def _send_download(self, send_body):
        try:
            stat = DOWNLOAD_FILE.stat()
        except FileNotFoundError:
            self.send_error(404, "Launcher installer not found")
            return

        start = 0
        end = stat.st_size - 1
        status = 200
        range_header = self.headers.get("Range")

        if range_header and range_header.startswith("bytes="):
            try:
                requested = range_header.removeprefix("bytes=").split(",", 1)[0]
                first, last = requested.split("-", 1)
                if first:
                    start = int(first)
                    end = int(last) if last else end
                else:
                    suffix_length = int(last)
                    start = max(0, stat.st_size - suffix_length)
                end = min(end, stat.st_size - 1)
                if start < 0 or start > end:
                    raise ValueError
                status = 206
            except ValueError:
                self.send_response(416)
                self.send_header("Content-Range", f"bytes */{stat.st_size}")
                self.end_headers()
                return

        length = end - start + 1
        self.send_response(status)
        self.send_header("Content-Type", "application/vnd.microsoft.portable-executable")
        self.send_header("Content-Disposition", f'attachment; filename="{DOWNLOAD_NAME}"')
        self.send_header("Content-Length", str(length))
        self.send_header("Last-Modified", formatdate(stat.st_mtime, usegmt=True))
        self.send_header("Accept-Ranges", "bytes")
        if status == 206:
            self.send_header("Content-Range", f"bytes {start}-{end}/{stat.st_size}")
        self.end_headers()

        if not send_body:
            return

        try:
            with DOWNLOAD_FILE.open("rb") as source:
                source.seek(start)
                remaining = length
                while remaining:
                    chunk = source.read(min(1024 * 1024, remaining))
                    if not chunk:
                        break
                    self.wfile.write(chunk)
                    remaining -= len(chunk)
        except (BrokenPipeError, ConnectionResetError):
            pass


if __name__ == "__main__":
    os.chdir(ROOT)
    handler = partial(DownloadHandler, directory=str(ROOT))
    ThreadingHTTPServer(("0.0.0.0", 25575), handler).serve_forever()
