"""
Python-Markdown extension: converts [[Wikilinks]] to standard Markdown links.

Mirrors the behavior of mkdocs-ezlinks-plugin's WikiLinkScanner, but as a
pure Markdown preprocessor (no MkDocs plugin API needed). Zensical handles
the resulting links natively.

Syntax:
    [[Page Name]]              → [Page Name](/page-name/)
    [[Page Name|Display Text]] → [Display Text](/page-name/)
    [[Page Name#anchor]]       → [Page Name](/page-name/#anchor)
    [[Page Name#anchor|Text]]  → [Text](/page-name/#anchor)
    ![[image.png]]             → ![image.png](/image.png)

Tolaria-compatible: when the vault root is the project root, links like
``[[docs/contributing/index]]`` are stripped of the ``docs/`` prefix and
converted to root-relative URLs (e.g. ``/contributing/``) that work from
any page regardless of depth.

Code blocks (fenced and inline) are skipped — wiki links inside them pass
through unchanged.
"""

from __future__ import annotations

import re
from markdown.preprocessors import Preprocessor
from markdown.extensions import Extension


# Regex for a wiki link. Borrowed from mkdocs-ezlinks-plugin's
# WikiLinkScanner with minor adjustments.
_WIKILINK_RE = re.compile(
    r"""
    (?P<image>\!?)                    # optional ! for image embeds
    \[\[                              # opening [[
        (?P<link>[^#\|\]]*?)          # target (everything before #, |, or ]])
        (?:\#(?P<anchor>[^\|\]]+)?)?  # optional #anchor
        (?:\|(?P<text>[^\]]+)?)?      # optional |display text
    \]\]                              # closing ]]
    """,
    re.VERBOSE,
)

# Match fenced code blocks or inline code spans (single capture group).
_CODE_RE = re.compile(
    r"(```.*?```|`[^`\n]+`)",
    re.DOTALL,
)

# Prefix to strip from Tolaria-generated links when the vault root is
# the project root (so links look like [[docs/foo/bar]]).
_DOCS_PREFIX = "docs/"


def _slugify(text: str) -> str:
    """Convert a human page name into a filename slug.

    Mirrors ezlinks: lowercase, spaces → hyphens, strip unsupported chars.
    Keeps forward slashes for subdirectory paths, dots for extensions, and CJK.
    """
    slug = text.strip().lower()
    slug = re.sub(r"\s+", "-", slug)
    # Keep: word chars, hyphens, dots, forward slashes, CJK
    slug = re.sub(r"[^\w./\u4e00-\u9fff\-]", "", slug)
    return slug


def _url_from_link(link: str) -> str:
    """Convert a wiki link target to a root-relative URL.

    Handles Tolaria-style full paths: strips ``docs/`` prefix,
    removes ``.md`` extension, collapses ``/index`` suffixes,
    slugifies each component, and prepends ``/``.
    """
    raw = link.strip()

    # Strip .md extension
    raw = re.sub(r"\.md$", "", raw, flags=re.IGNORECASE)

    # Strip docs/ prefix (Tolaria vault root = project root)
    if raw.lower().startswith(_DOCS_PREFIX):
        raw = raw[len(_DOCS_PREFIX) :]

    # Collapse trailing /index — section index pages resolve to the dir
    raw = re.sub(r"/index$", "", raw)

    if not raw:
        return "/"

    # Slugify each path component
    parts = [_slugify(p) for p in raw.split("/") if p]
    return "/" + "/".join(parts) + "/"


def _display_name(link: str) -> str:
    """Derive a human-readable title from a wiki link path.

    ``[[docs/contributing/index]]`` → ``Contributing``
    ``[[docs/strategies/collective-awakening]]`` → ``Collective Awakening``
    ``[[Contributing]]`` → ``Contributing``
    """
    raw = link.strip()

    # Strip .md extension
    raw = re.sub(r"\.md$", "", raw, flags=re.IGNORECASE)

    # Strip docs/ prefix
    if raw.lower().startswith(_DOCS_PREFIX):
        raw = raw[len(_DOCS_PREFIX) :]

    parts = [p for p in raw.split("/") if p]
    if not parts:
        return link

    # If the last component is "index", use the parent directory name
    if parts[-1].lower() == "index":
        name = parts[-2] if len(parts) >= 2 else parts[-1]
    else:
        name = parts[-1]

    # Replace hyphens/underscores with spaces, title-case
    name = name.replace("-", " ").replace("_", " ")
    return name.title()


class WikilinksPreprocessor(Preprocessor):
    """Preprocessor that converts [[wikilinks]] to root-relative [text](/url/)."""

    def run(self, lines: list[str]) -> list[str]:
        text = "\n".join(lines)

        # Walk through the text, skipping code spans. Use finditer to
        # extract code regions, then transform wiki links in the gaps.
        result: list[str] = []
        cursor = 0
        for m in _CODE_RE.finditer(text):
            before = text[cursor : m.start()]
            if before:
                result.append(_WIKILINK_RE.sub(self._replace, before))
            result.append(m.group(0))
            cursor = m.end()

        tail = text[cursor:]
        if tail:
            result.append(_WIKILINK_RE.sub(self._replace, tail))

        return "\n".join(result).split("\n")

    def _replace(self, match: re.Match) -> str:
        groups = match.groupdict()
        is_image = groups.get("image") or ""
        link = groups.get("link") or ""
        anchor = groups.get("anchor") or ""
        text = groups.get("text") or (link if is_image else _display_name(link)) or anchor

        if not (link or text or anchor):
            return match.group(0)

        # Build the href: root-relative URL for pages; relative for images
        if is_image:
            # Images: keep filename, strip docs/ prefix, make root-relative
            raw = link.strip()
            if raw.lower().startswith(_DOCS_PREFIX):
                raw = raw[len(_DOCS_PREFIX) :]
            # Non-image assets might have extensions; keep them
            href = raw if "." in raw else _slugify(raw)
            if not href.startswith("/"):
                href = "/" + href
        else:
            href = _url_from_link(link)

        # Append anchor if present
        if anchor:
            anchor_slug = _slugify(anchor)
            if anchor_slug:
                href = href.rstrip("/") + "#" + anchor_slug

        if is_image:
            return f"![{text}]({href})"
        else:
            return f"[{text}]({href})"


class WikilinksExtension(Extension):
    """Register the WikilinksPreprocessor."""

    def extendMarkdown(self, md):
        # Priority 35: after normalize_whitespace (30), before html_block (20)
        md.preprocessors.register(WikilinksPreprocessor(md), "wikilinks", 35)


def makeExtension(**kwargs):
    return WikilinksExtension(**kwargs)
