from __future__ import annotations

import json
import sys
import traceback
from email import policy
from email.parser import BytesParser
from http.server import BaseHTTPRequestHandler
from pathlib import Path
from typing import Any
from urllib.parse import quote

ROOT_DIR = Path(__file__).resolve().parents[1]
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from server.app_service import AppInputError, UploadedFile  # noqa: E402


def parse_form(handler: BaseHTTPRequestHandler) -> dict[str, Any]:
    content_type = handler.headers.get("content-type", "")
    if not content_type.startswith("multipart/form-data"):
        raise AppInputError("请求格式不正确，请刷新页面后重试。")
    length = int(handler.headers.get("content-length", "0") or "0")
    body = handler.rfile.read(length)
    raw_message = (
        f"Content-Type: {content_type}\r\n"
        "MIME-Version: 1.0\r\n"
        "\r\n"
    ).encode("utf-8") + body
    message = BytesParser(policy=policy.default).parsebytes(raw_message)

    texts: dict[str, list[str]] = {}
    files: dict[str, list[UploadedFile]] = {}
    if not message.is_multipart():
        raise AppInputError("请求格式不完整，请刷新页面后重试。")
    for part in message.iter_parts():
        if part.get_content_disposition() != "form-data":
            continue
        name = part.get_param("name", header="content-disposition")
        if not name:
            continue
        filename = part.get_filename()
        payload = part.get_payload(decode=True) or b""
        if filename:
            files.setdefault(name, []).append(UploadedFile(name=Path(filename.replace("\\", "/")).name, data=payload))
        else:
            charset = part.get_content_charset() or "utf-8"
            texts.setdefault(name, []).append(payload.decode(charset, errors="replace"))

    settings_text = (texts.get("settings") or ["{}"])[0]
    try:
        settings = json.loads(settings_text) if settings_text else {}
    except json.JSONDecodeError:
        raise AppInputError("页面设置解析失败，请刷新页面后重试。")
    return {
        "use_sample": (texts.get("use_sample") or ["0"])[0] == "1",
        "uploaded_files": files.get("files", []),
        "config_file": (files.get("business_config") or [None])[0],
        "settings": settings,
        "action": (texts.get("action") or ["preview"])[0],
    }


def send_json(handler: BaseHTTPRequestHandler, payload: dict[str, Any], status: int = 200) -> None:
    body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    handler.send_response(status)
    handler.send_header("content-type", "application/json; charset=utf-8")
    handler.send_header("cache-control", "no-store")
    handler.send_header("content-length", str(len(body)))
    handler.end_headers()
    handler.wfile.write(body)


def send_binary(
    handler: BaseHTTPRequestHandler,
    body: bytes,
    *,
    filename: str,
    content_type: str,
    status: int = 200,
) -> None:
    disposition = "attachment; filename*=UTF-8''" + quote(filename)
    handler.send_response(status)
    handler.send_header("content-type", content_type)
    handler.send_header("content-disposition", disposition)
    handler.send_header("cache-control", "no-store")
    handler.send_header("content-length", str(len(body)))
    handler.end_headers()
    handler.wfile.write(body)


def send_options(handler: BaseHTTPRequestHandler) -> None:
    handler.send_response(204)
    handler.send_header("allow", "POST, GET, OPTIONS")
    handler.end_headers()


def handle_exception(handler: BaseHTTPRequestHandler, exc: Exception) -> None:
    if isinstance(exc, AppInputError):
        send_json(handler, {"ok": False, "error": str(exc)}, status=400)
        return
    traceback.print_exc()
    send_json(handler, {"ok": False, "error": f"服务端计算失败：{exc}"}, status=500)
