"""Deterministic Gitea double used by the release-artifact browser journey."""

from __future__ import annotations

import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from threading import Event
from urllib.parse import parse_qs, urlsplit


REPOSITORY = {
    "id": 7,
    "name": "mobile",
    "full_name": "acme/mobile",
    "description": "Mobile filing acceptance repository",
    "html_url": "http://127.0.0.1/acme/mobile",
    "owner": {"login": "acme"},
}
USER = {"id": 1, "login": "timmy", "full_name": "Timmy"}
AVAILABLE_ISSUES = [
    {
        "id": 101,
        "number": 41,
        "title": "Ship mobile capture",
        "body": "Complete the capture flow on a phone.",
        "state": "open",
        "html_url": "http://127.0.0.1/acme/mobile/issues/41",
        "repository": REPOSITORY,
        "user": USER,
        "assignees": [],
        "labels": [{"name": "P1"}],
        "updated_at": "2026-08-15T12:00:00Z",
    },
    {
        "id": 102,
        "number": 42,
        "title": "Polish desktop filters",
        "body": "Keep the desktop filter controls clear.",
        "state": "open",
        "html_url": "http://127.0.0.1/acme/mobile/issues/42",
        "repository": REPOSITORY,
        "user": USER,
        "assignees": [],
        "labels": [],
        "updated_at": "2026-08-15T11:00:00Z",
    },
]


class FakeGiteaServer(ThreadingHTTPServer):
    def __init__(self, address: tuple[str, int]):
        super().__init__(address, FakeGiteaHandler)
        self.created_issues: list[dict] = []
        self.issue_creation_enabled = False
        self.issue_creation_ready = Event()
        self.assigned_issue_numbers = [issue["number"] for issue in AVAILABLE_ISSUES]
        self.comments: list[tuple[int, str]] = []
        self.activity_comments: dict[int, list[dict]] = {}
        self.edited_comments: list[tuple[int, int, str]] = []
        self.requests: list[tuple[str, str]] = []


class FakeGiteaHandler(BaseHTTPRequestHandler):
    server: FakeGiteaServer

    def log_message(self, _format: str, *_args: object) -> None:
        return

    def _json(self, status: int, payload: object, **headers: str) -> None:
        body = json.dumps(payload).encode()
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        for name, value in headers.items():
            self.send_header(name, value)
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self) -> None:  # noqa: N802 - BaseHTTPRequestHandler API
        parsed = urlsplit(self.path)
        path = parsed.path
        query = parse_qs(parsed.query)
        self.server.requests.append(("GET", self.path))
        if path == "/api/v1/user":
            self._json(200, USER)
        elif path == "/api/v1/user/repos":
            self._json(200, [REPOSITORY], **{"X-Total-Count": "1"})
        elif path in {"/api/v1/repos/acme/mobile", "/api/v1/repos/acme/mobile/"}:
            self._json(200, REPOSITORY)
        elif path == "/api/v1/repos/search":
            self._json(200, {"data": [REPOSITORY], "ok": True})
        elif path == "/api/v1/repos/acme/mobile/assignees":
            self._json(200, [
                USER,
                {"id": 2, "login": "alex", "full_name": "Alexander", "active": True},
            ])
        elif path == "/api/v1/repos/issues/search":
            is_assigned_scan = query.get("assigned") == ["true"] and query.get("type") == ["issues"]
            is_available_scan = not any(
                name in query for name in ("assigned", "created", "review_requested", "q")
            ) and query.get("type") == ["issues"]
            assigned = [
                {**issue, "assignees": [USER]}
                for issue in AVAILABLE_ISSUES
                if issue["number"] in self.server.assigned_issue_numbers
            ]
            available = [
                issue for issue in AVAILABLE_ISSUES
                if issue["number"] not in self.server.assigned_issue_numbers
            ]
            issues = assigned if is_assigned_scan else available if is_available_scan else []
            self._json(200, issues, **{"X-Total-Count": str(len(issues))})
        elif path.startswith("/api/v1/repos/acme/mobile/issues/comments/"):
            try:
                comment_id = int(path.rsplit("/", 1)[-1])
            except ValueError:
                comment_id = 0
            comment = next((item for comments in self.server.activity_comments.values()
                            for item in comments if item.get("id") == comment_id), None)
            self._json(200, {**comment, "user": USER}) if comment else self._json(404, {"message": "not found"})
        elif path.startswith("/api/v1/repos/acme/mobile/issues/") and path.endswith("/comments"):
            try:
                number = int(path.split("/")[-2])
            except ValueError:
                number = 0
            comments = self.server.activity_comments.get(number, [])
            self._json(200, comments, **{"X-Total-Count": str(len(comments))})
        elif path.startswith("/api/v1/repos/acme/mobile/issues/") and path.endswith("/dependencies"):
            self._json(200, [])
        elif path.startswith("/api/v1/repos/acme/mobile/issues/"):
            try:
                number = int(path.rsplit("/", 1)[-1])
            except ValueError:
                number = 0
            issue = next((item for item in AVAILABLE_ISSUES if item["number"] == number), None)
            if issue and number in self.server.assigned_issue_numbers:
                issue = {**issue, "assignees": [USER]}
            self._json(200, issue) if issue else self._json(404, {"message": "not found"})
        elif path.startswith("/api/v1/"):
            self._json(200, [], **{"X-Total-Count": "0"})
        else:
            self._json(404, {"message": "not found"})

    def do_POST(self) -> None:  # noqa: N802 - BaseHTTPRequestHandler API
        path = urlsplit(self.path).path
        self.server.requests.append(("POST", self.path))
        length = int(self.headers.get("Content-Length", "0"))
        payload = json.loads(self.rfile.read(length) or b"{}")
        if path.startswith("/api/v1/repos/acme/mobile/issues/") and path.endswith("/comments"):
            try:
                number = int(path.split("/")[-2])
            except ValueError:
                self._json(404, {"message": "not found"})
                return
            body = str(payload.get("body", ""))
            self.server.comments.append((number, body))
            self._json(
                201,
                {
                    "id": len(self.server.comments),
                    "body": body,
                    "user": USER,
                    "created_at": "2026-08-16T20:00:00Z",
                    "updated_at": "2026-08-16T20:00:00Z",
                    "html_url": f"http://127.0.0.1/acme/mobile/issues/{number}#issuecomment-1",
                },
            )
            return
        if path != "/api/v1/repos/acme/mobile/issues":
            self._json(404, {"message": "not found"})
            return
        if not self.server.issue_creation_enabled:
            self.server.issue_creation_ready.wait(timeout=45)
        if not self.server.issue_creation_enabled:
            self._json(503, {"message": "release journey is still offline"})
            return
        self.server.created_issues.append(payload)
        assignee = payload.get("assignee")
        self._json(
            201,
            {
                "id": 101,
                "number": 41,
                "title": payload.get("title", ""),
                "body": payload.get("body", ""),
                "state": "open",
                "html_url": "http://127.0.0.1/acme/mobile/issues/41",
                "assignees": [{"login": assignee}] if assignee else [],
                "labels": [],
                "milestone": None,
                "due_date": payload.get("due_date"),
                "updated_at": "2026-08-15T12:00:00Z",
            },
        )

    def do_PATCH(self) -> None:  # noqa: N802 - BaseHTTPRequestHandler API
        path = urlsplit(self.path).path
        self.server.requests.append(("PATCH", self.path))
        length = int(self.headers.get("Content-Length", "0"))
        payload = json.loads(self.rfile.read(length) or b"{}")
        parts = path.strip("/").split("/")
        if len(parts) == 8 and parts[:7] == ["api", "v1", "repos", "acme", "mobile", "issues", "comments"]:
            try:
                comment_id = int(parts[7])
            except ValueError:
                self._json(404, {"message": "not found"})
                return
            match = next(((number, item) for number, comments in self.server.activity_comments.items()
                          for item in comments if item.get("id") == comment_id), None)
            if match is None:
                self._json(404, {"message": "not found"})
                return
            number, comment = match
            body = str(payload.get("body", ""))
            comment["body"] = body
            self.server.edited_comments.append((number, comment_id, body))
            self._json(200, {**comment, "user": USER, "updated_at": "2026-08-18T01:00:00Z"})
            return
        if len(parts) == 9 and parts[:5] == ["api", "v1", "repos", "acme", "mobile"] and parts[5] == "issues" and parts[7] == "comments":
            try:
                number, comment_id = int(parts[6]), int(parts[8])
            except ValueError:
                self._json(404, {"message": "not found"})
                return
            comments = self.server.activity_comments.get(number, [])
            comment = next((item for item in comments if item.get("id") == comment_id), None)
            if comment is None:
                self._json(404, {"message": "not found"})
                return
            body = str(payload.get("body", ""))
            comment["body"] = body
            self.server.edited_comments.append((number, comment_id, body))
            self._json(200, {**comment, "user": USER, "updated_at": "2026-08-18T01:00:00Z"})
            return
        if not path.startswith("/api/v1/repos/acme/mobile/issues/"):
            self._json(404, {"message": "not found"})
            return
        try:
            number = int(path.rsplit("/", 1)[-1])
        except ValueError:
            self._json(404, {"message": "not found"})
            return
        issue = next((item for item in AVAILABLE_ISSUES if item["number"] == number), None)
        if issue is None:
            self._json(404, {"message": "not found"})
            return
        assignee = payload.get("assignee")
        self.server.assigned_issue_numbers.append(number)
        self._json(200, {**issue, "assignees": [{"login": assignee}] if assignee else []})
