from __future__ import annotations

import json
import subprocess
import sys
from datetime import datetime, timezone
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path


ROOT = Path(__file__).resolve().parent
SUBMIT_DIR = ROOT / "preview_exports" / "assembly"
SUBMIT_FILE = SUBMIT_DIR / "submitted_parameters.json"
ENGINE_SCRIPT = ROOT / "tools" / "standalone_platform_engine.py"
EXPORT_SCRIPT = ROOT / "tools" / "standalone_export_engine.py"


class PreviewHandler(SimpleHTTPRequestHandler):
    def end_headers(self) -> None:
        self.send_header("Cache-Control", "no-store")
        super().end_headers()

    def do_POST(self) -> None:
        if self.path not in {"/api/submit-parameters", "/api/apply-parameters", "/api/engine-parameters", "/api/export-files"}:
            self.send_error(404, "Unknown endpoint")
            return

        length = int(self.headers.get("Content-Length", "0"))
        raw = self.rfile.read(length)
        try:
            payload = json.loads(raw.decode("utf-8"))
        except json.JSONDecodeError as exc:
            self.send_error(400, f"Invalid JSON: {exc}")
            return

        SUBMIT_DIR.mkdir(parents=True, exist_ok=True)
        payload["serverReceivedAt"] = datetime.now(timezone.utc).isoformat()
        SUBMIT_FILE.write_text(json.dumps(payload, indent=2), encoding="utf-8")

        if self.path == "/api/export-files":
            try:
                export_result = subprocess.run(
                    [sys.executable, str(EXPORT_SCRIPT)],
                    cwd=ROOT,
                    text=True,
                    capture_output=True,
                    timeout=240,
                    check=True,
                )
            except subprocess.CalledProcessError as exc:
                message = {
                    "ok": False,
                    "stage": "export",
                    "returncode": exc.returncode,
                    "stdout": exc.stdout[-4000:],
                    "stderr": exc.stderr[-4000:],
                }
                body = json.dumps(message, indent=2).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(body)))
                self.end_headers()
                self.wfile.write(body)
                return
            try:
                response = json.loads(export_result.stdout)
            except json.JSONDecodeError:
                response = {"ok": True, "exportStdout": export_result.stdout[-4000:]}
            body = json.dumps(response).encode("utf-8")
            self.send_response(200)
            self.send_header("Content-Type", "application/json; charset=utf-8")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
            return
        if self.path == "/api/engine-parameters":
            try:
                engine_result = subprocess.run(
                    [sys.executable, str(ENGINE_SCRIPT), str(SUBMIT_FILE)],
                    cwd=ROOT,
                    text=True,
                    capture_output=True,
                    timeout=30,
                    check=True,
                )
            except subprocess.CalledProcessError as exc:
                message = {
                    "ok": False,
                    "stage": "engine",
                    "returncode": exc.returncode,
                    "stdout": exc.stdout[-4000:],
                    "stderr": exc.stderr[-4000:],
                }
                body = json.dumps(message, indent=2).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(body)))
                self.end_headers()
                self.wfile.write(body)
                return
            apply_result = None
            catalog_result = None
        elif self.path == "/api/apply-parameters":
            try:
                apply_result = subprocess.run(
                    [
                        "powershell",
                        "-NoProfile",
                        "-ExecutionPolicy",
                        "Bypass",
                        "-File",
                        str(ROOT / "tools" / "apply_parameters_and_export.ps1"),
                        "-PayloadPath",
                        str(SUBMIT_FILE),
                    ],
                    cwd=ROOT,
                    text=True,
                    capture_output=True,
                    timeout=240,
                    check=True,
                )
                catalog_result = subprocess.run(
                    [sys.executable, str(ROOT / "tools" / "build_live_update_catalog.py")],
                    cwd=ROOT,
                    text=True,
                    capture_output=True,
                    timeout=180,
                    check=True,
                )
            except subprocess.CalledProcessError as exc:
                message = {
                    "ok": False,
                    "stage": "apply" if "apply_result" not in locals() else "catalog",
                    "returncode": exc.returncode,
                    "stdout": exc.stdout[-4000:],
                    "stderr": exc.stderr[-4000:],
                }
                body = json.dumps(message, indent=2).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(body)))
                self.end_headers()
                self.wfile.write(body)
                return
            except subprocess.TimeoutExpired as exc:
                message = {
                    "ok": False,
                    "stage": "timeout",
                    "stdout": (exc.stdout or "")[-4000:],
                    "stderr": (exc.stderr or "")[-4000:],
                }
                body = json.dumps(message, indent=2).encode("utf-8")
                self.send_response(504)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(body)))
                self.end_headers()
                self.wfile.write(body)
                return
        else:
            apply_result = None
            catalog_result = None
            engine_result = None

        response = {
            "ok": True,
            "path": str(SUBMIT_FILE.relative_to(ROOT)).replace("\\", "/"),
            "changedCount": payload.get("changedCount", 0),
            "updatedAssembly": (
                "preview_exports/assembly/roof_mount_platform_engine_assembly.json"
                if self.path == "/api/engine-parameters"
                else "preview_exports/assembly/roof_mount_platform_live_assembly.json"
                if self.path == "/api/apply-parameters"
                else None
            ),
            "engineStdout": engine_result.stdout[-4000:] if "engine_result" in locals() and engine_result else "",
            "applyStdout": apply_result.stdout[-2000:] if apply_result else "",
            "catalogStdout": catalog_result.stdout[-2000:] if catalog_result else "",
        }
        body = json.dumps(response).encode("utf-8")
        self.send_response(200)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


def main() -> None:
    server = ThreadingHTTPServer(("0.0.0.0", 8765), PreviewHandler)
    print("Serving preview on http://0.0.0.0:8765/")
    print("Open from this PC: http://127.0.0.1:8765/preview_exports/assembly/assembly_viewer.html")
    server.serve_forever()


if __name__ == "__main__":
    main()
