#!/usr/bin/env python3
"""Reference Hummic upload receiver.

A minimal, dependency-free HTTP endpoint for Hummic P0. It accepts the device's
multipart/form-data upload, stores the file plus metadata, and returns the JSON
the firmware expects. Standard library only, so it runs on any Python 3.8+
(no reliance on the removed `cgi` module).
"""
import argparse
import json
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from uuid import uuid4


def _disposition_param(disposition, key):
    """Pull a parameter (e.g. name= or filename=) out of Content-Disposition."""
    marker = key + "="
    for part in disposition.split(";"):
        part = part.strip()
        if part.startswith(marker):
            value = part[len(marker):].strip()
            if len(value) >= 2 and value[0] == '"' and value[-1] == '"':
                value = value[1:-1]
            return value
    return None


def parse_multipart(body, boundary):
    """Split a multipart/form-data body into (fields, files), no cgi required.

    fields: name -> str ; files: name -> (filename, bytes). Exactly one leading
    and trailing CRLF of framing is stripped so binary payloads stay intact.
    """
    fields, files = {}, {}
    delimiter = b"--" + boundary.encode("latin-1")
    for segment in body.split(delimiter):
        if segment.startswith(b"\r\n"):
            segment = segment[2:]
        if segment.endswith(b"\r\n"):
            segment = segment[:-2]
        if not segment or segment == b"--":
            continue
        head, sep, content = segment.partition(b"\r\n\r\n")
        if not sep:
            continue
        disposition = ""
        for line in head.split(b"\r\n"):
            name, _, value = line.partition(b":")
            if name.strip().lower() == b"content-disposition":
                disposition = value.strip().decode("latin-1")
                break
        name = _disposition_param(disposition, "name")
        if not name:
            continue
        filename = _disposition_param(disposition, "filename")
        if filename is not None:
            files[name] = (filename, content)
        else:
            fields[name] = content.decode("utf-8", "replace")
    return fields, files


class UploadHandler(BaseHTTPRequestHandler):
    server_version = "HummicUploadServer/0.2"

    def _send_json(self, status, payload):
        body = json.dumps(payload, separators=(",", ":")).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        if self.path != "/health":
            self._send_json(HTTPStatus.NOT_FOUND, {"ok": False, "error": "not_found"})
            return
        self._send_json(HTTPStatus.OK, {"ok": True})

    def do_POST(self):
        if self.path != "/upload":
            self._send_json(HTTPStatus.NOT_FOUND, {"ok": False, "error": "not_found"})
            return

        expected_token = self.server.expected_token
        if expected_token:
            if self.headers.get("Authorization", "") != f"Bearer {expected_token}":
                self._send_json(HTTPStatus.UNAUTHORIZED, {"ok": False, "error": "invalid_token"})
                return

        content_type = self.headers.get("Content-Type", "")
        if "multipart/form-data" not in content_type or "boundary=" not in content_type:
            self._send_json(HTTPStatus.BAD_REQUEST, {"ok": False, "error": "expected_multipart"})
            return
        boundary = content_type.split("boundary=", 1)[1].strip().strip('"')

        length = int(self.headers.get("Content-Length", "0") or "0")
        body = self.rfile.read(length) if length > 0 else b""
        fields, files = parse_multipart(body, boundary)

        if "file" not in files:
            self._send_json(HTTPStatus.BAD_REQUEST, {"ok": False, "error": "file_missing"})
            return

        recording_id = (
            fields.get("recording_id")
            or self.headers.get("X-Hummic-Recording-Id")
            or uuid4().hex
        )
        safe_recording_id = "".join(
            ch for ch in recording_id if ch.isalnum() or ch in ("-", "_")
        )[:80] or uuid4().hex

        upload_dir = self.server.upload_dir / safe_recording_id
        upload_dir.mkdir(parents=True, exist_ok=True)

        filename, file_bytes = files["file"]
        filename = Path(filename or f"{safe_recording_id}.ogg").name
        file_path = upload_dir / filename
        file_path.write_bytes(file_bytes)

        metadata = {
            "headers": {
                "X-Hummic-Device-Id": self.headers.get("X-Hummic-Device-Id", ""),
                "X-Hummic-Recording-Id": self.headers.get("X-Hummic-Recording-Id", ""),
            },
            "fields": fields,
            "file": str(file_path),
            "bytes": len(file_bytes),
        }
        (upload_dir / "metadata.json").write_text(
            json.dumps(metadata, indent=2, ensure_ascii=False), encoding="utf-8"
        )
        self._send_json(HTTPStatus.OK, {"ok": True, "upload_id": safe_recording_id})


def main():
    parser = argparse.ArgumentParser(description="Reference Hummic upload receiver")
    parser.add_argument("--host", default="127.0.0.1")
    parser.add_argument("--port", type=int, default=8789)
    parser.add_argument("--token", default="")
    parser.add_argument("--upload-dir", default=str(Path(__file__).with_name("uploads")))
    args = parser.parse_args()

    server = ThreadingHTTPServer((args.host, args.port), UploadHandler)
    server.expected_token = args.token
    server.upload_dir = Path(args.upload_dir)
    server.upload_dir.mkdir(parents=True, exist_ok=True)
    print(f"Hummic upload server listening on http://{args.host}:{args.port}/upload")
    print(f"Health check:                    http://{args.host}:{args.port}/health")
    server.serve_forever()


if __name__ == "__main__":
    main()
