from __future__ import annotations

import base64
import json
import os
import sys
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import urlparse

REPO_ROOT = Path(__file__).resolve().parents[2]
WSCRAPER_SRC = REPO_ROOT / "bin" / "wscraper" / "src"
if str(WSCRAPER_SRC) not in sys.path:
    sys.path.insert(0, str(WSCRAPER_SRC))

from wscraper.registry import get_tracker, list_trackers, normalize_tracker

HOST = os.environ.get("WSCRAPER_SERVICE_HOST", "0.0.0.0")
PORT = int(os.environ.get("WSCRAPER_SERVICE_PORT", "8787"))
TOKEN = os.environ.get("WSCRAPER_SERVICE_TOKEN", "")


def json_response(handler: BaseHTTPRequestHandler, status: int, payload: dict) -> 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("Content-Length", str(len(body)))
    handler.end_headers()
    handler.wfile.write(body)


def parse_json_body(handler: BaseHTTPRequestHandler) -> dict:
    length = int(handler.headers.get("Content-Length", "0"))
    raw = handler.rfile.read(length) if length > 0 else b"{}"
    return json.loads(raw.decode("utf-8"))


def require_auth(handler: BaseHTTPRequestHandler) -> bool:
    if not TOKEN:
        return True
    auth_header = handler.headers.get("Authorization", "")
    if auth_header == f"Bearer {TOKEN}":
        return True
    json_response(handler, HTTPStatus.UNAUTHORIZED, {"error": "Unauthorized"})
    return False


def normalize_payload(payload: dict) -> tuple[str, str, dict, str | None]:
    tracker_key = normalize_tracker(str(payload.get("tracker", "")))
    cookie = str(payload.get("cookie", "")).strip()
    if not cookie:
        raise ValueError("Cookie is required")
    item = payload.get("item")
    if item is None:
        item = {}
    if not isinstance(item, dict):
        raise ValueError("Item payload must be an object")
    wishlist_url = payload.get("wishlistUrl")
    if wishlist_url is not None:
        wishlist_url = str(wishlist_url).strip() or None
    return tracker_key, cookie, item, wishlist_url


class Handler(BaseHTTPRequestHandler):
    server_version = "wscraper-service/2.0"

    def do_GET(self) -> None:  # noqa: N802
        parsed = urlparse(self.path)
        if parsed.path == "/health":
            if not require_auth(self):
                return
            json_response(self, HTTPStatus.OK, {"ok": True, "service": "wscraper-service"})
            return
        if parsed.path == "/trackers":
            if not require_auth(self):
                return
            json_response(
                self,
                HTTPStatus.OK,
                {"items": [{"key": tracker.key, "label": tracker.label} for tracker in list_trackers()]},
            )
            return
        json_response(self, HTTPStatus.NOT_FOUND, {"error": "Not found"})

    def do_POST(self) -> None:  # noqa: N802
        if not require_auth(self):
            return

        parsed = urlparse(self.path)
        try:
            payload = parse_json_body(self)
            tracker_key, cookie, item, wishlist_url = normalize_payload(payload)
            tracker = get_tracker(tracker_key)

            if parsed.path == "/bookmarks":
                items = tracker.get_bookmarks(cookie, wishlist_url=wishlist_url)
                json_response(self, HTTPStatus.OK, {"tracker": tracker_key, "items": items})
                return

            if parsed.path == "/download":
                result = tracker.download_torrent(cookie, item, wishlist_url=wishlist_url)
                json_response(
                    self,
                    HTTPStatus.OK,
                    {
                        "tracker": tracker_key,
                        "filename": result["filename"],
                        "contentBase64": base64.b64encode(result["data"]).decode("ascii"),
                    },
                )
                return

            if parsed.path == "/remove-bookmark":
                tracker.remove_bookmark(cookie, item, wishlist_url=wishlist_url)
                json_response(self, HTTPStatus.OK, {"tracker": tracker_key, "ok": True})
                return

            json_response(self, HTTPStatus.NOT_FOUND, {"error": "Not found"})
        except Exception as error:  # noqa: BLE001
            json_response(self, HTTPStatus.BAD_REQUEST, {"error": str(error)})

    def log_message(self, fmt: str, *args) -> None:
        print(f"[wscraper-service] {self.address_string()} - {fmt % args}")


def main() -> None:
    server = ThreadingHTTPServer((HOST, PORT), Handler)
    print(f"wscraper-service listening on http://{HOST}:{PORT}")
    server.serve_forever()


if __name__ == "__main__":
    main()
