from __future__ import annotations

import re
import urllib.parse
from typing import Any


PLATFORM_DOC_RE = re.compile(r"/db/(v(?:8|83|85)\d*doc)(?:/|$)", flags=re.IGNORECASE)
BOOKMARK_PATH_RE = re.compile(r"/bookmark/([^/]+)/([^/?#]+)", flags=re.IGNORECASE)
CONTENT_PATH_RE = re.compile(r"/content/(-?\d+)/(?:hdoc|\d+)", flags=re.IGNORECASE)
HASH_BOOKMARK_RE = re.compile(r"^#?bookmark:([^:]+):([^:]+)$", flags=re.IGNORECASE)
HASH_CONTENT_RE = re.compile(r"^#?content:([^:]+):([^:]+)$", flags=re.IGNORECASE)


def platform_doc_id_from_url(url: str) -> str | None:
    match = PLATFORM_DOC_RE.search(urllib.parse.urlparse(url).path)
    return match.group(1).lower() if match else None


def platform_version_from_doc_id(doc_id: str | None) -> str | None:
    if not doc_id:
        return None
    doc_id = doc_id.lower()
    if doc_id == "v8doc":
        return "8.x"
    match = re.fullmatch(r"v83(\d+)doc", doc_id)
    if match:
        patch = int(match.group(1))
        return f"8.3.{patch}"
    match = re.fullmatch(r"v85(\d+)doc", doc_id)
    if match:
        patch = int(match.group(1))
        return f"8.5.{patch}"
    match = re.fullmatch(r"v8(\d+)doc", doc_id)
    if match:
        patch = int(match.group(1))
        return f"8.{patch}"
    return None


def platform_version_from_url(url: str) -> str | None:
    return platform_version_from_doc_id(platform_doc_id_from_url(url))


def parse_doc_coordinate(url: str) -> dict[str, str | None]:
    parsed = urllib.parse.urlparse(url)
    path = parsed.path
    fragment = urllib.parse.unquote(parsed.fragment or "")
    coordinate: dict[str, str | None] = {
        "platform_doc_id": platform_doc_id_from_url(url),
        "platform_version": platform_version_from_url(url),
        "doc_book": None,
        "doc_bookmark": None,
        "doc_content_id": None,
        "doc_coordinate": None,
    }

    bookmark = BOOKMARK_PATH_RE.search(path)
    if bookmark:
        coordinate["doc_book"] = bookmark.group(1)
        coordinate["doc_bookmark"] = bookmark.group(2)
    else:
        hash_bookmark = HASH_BOOKMARK_RE.match(fragment)
        if hash_bookmark:
            coordinate["doc_book"] = hash_bookmark.group(1)
            coordinate["doc_bookmark"] = hash_bookmark.group(2)

    content = CONTENT_PATH_RE.search(path)
    if content:
        coordinate["doc_content_id"] = content.group(1)
    else:
        hash_content = HASH_CONTENT_RE.match(fragment)
        if hash_content:
            coordinate["doc_book"] = coordinate["doc_book"] or hash_content.group(1)
            coordinate["doc_content_id"] = hash_content.group(2)

    parts = [
        coordinate.get("platform_doc_id"),
        coordinate.get("doc_book"),
        coordinate.get("doc_bookmark") or coordinate.get("doc_content_id"),
    ]
    if any(parts):
        coordinate["doc_coordinate"] = ":".join(part or "_" for part in parts)
    return coordinate


def materialize_doc_url(url: str) -> str:
    parsed = urllib.parse.urlparse(url)
    fragment = urllib.parse.unquote(parsed.fragment or "")
    if not fragment:
        return url

    hash_bookmark = HASH_BOOKMARK_RE.match(fragment)
    if hash_bookmark:
        path = parsed.path.rstrip("/") + f"/bookmark/{hash_bookmark.group(1)}/{hash_bookmark.group(2)}"
        return urllib.parse.urlunparse(parsed._replace(path=path, fragment=""))

    hash_content = HASH_CONTENT_RE.match(fragment)
    if hash_content:
        content_id = hash_content.group(2)
        path = parsed.path.rstrip("/") + f"/content/{content_id}/hdoc"
        return urllib.parse.urlunparse(parsed._replace(path=path, fragment=""))

    return urllib.parse.urlunparse(parsed._replace(fragment=""))


def merge_platform_metadata(record: dict[str, Any], url: str) -> dict[str, Any]:
    coordinate = parse_doc_coordinate(url)
    merged = dict(record)
    for key, value in coordinate.items():
        if value and not merged.get(key):
            merged[key] = value
    if not merged.get("platform_family") and merged.get("platform_doc_id"):
        merged["platform_family"] = "1C:Enterprise 8"
    return merged
