from __future__ import annotations

"""
Fixer for `*-class-sidebar.html` files.

Purpose:
Class sidebar files occasionally contain duplicated folder prefixes in their
href attributes. This occurs when Dartdoc generates sidebar navigation links
that accidentally repeat the directory structure. Example:

    Folder: adapters
    Incorrect generated link: adapters/adapters/MyClass.html
    Correct normalized link:  adapters/MyClass.html

Rule:
If an href begins with "{sidebar_folder}/", that prefix is removed exactly once.
This preserves valid relative paths while eliminating duplicated segments.

Ignored cases:
- Anchor links (starting with '#'),
- External URLs (http, https),
- JavaScript pseudo URLs ("javascript:...").
These are never modified by this fixer.
"""

from pathlib import Path

from bs4 import BeautifulSoup

from .links import is_anchor, is_external_or_js


def fix_class_sidebar_file(html_path: Path) -> int:
    """
    Fix a single `*-class-sidebar.html` file by normalizing sidebar href links.

    The function performs the following steps:
    1. Load and parse the HTML file.
    2. Identify links that contain duplicated folder prefixes.
    3. Remove exactly one instance of the duplicated "{folder}/" prefix.
    4. Preserve any anchor fragments (e.g., "#constructors") when rewriting links.
    5. Write the modified HTML back to disk only if changes were made.

    Parameters:
        html_path: Path to the sidebar HTML file.

    Returns:
        The number of sidebar links that were modified.
        Returns 0 if the file does not exist or if no links required changes.
    """
    html_path = html_path.resolve()
    if not html_path.exists():
        return 0

    raw = html_path.read_text(encoding="utf-8", errors="ignore")
    soup = BeautifulSoup(raw, "lxml")

    # The name of the directory containing this sidebar.
    # Used to detect duplicated prefixes such as "folder/folder/SomeClass.html".
    folder = html_path.parent.name
    prefix = f"{folder}/"

    changed = 0

    # Iterate through all <a> tags that contain an href attribute.
    for a in soup.find_all("a", href=True):
        href = a["href"]
        if not href:
            continue

        # Skip anchor-only links or external/JavaScript URLs.
        if is_anchor(href) or is_external_or_js(href):
            continue

        # Normalize backslashes to forward slashes to ensure consistent path analysis.
        normalized = href.replace("\\", "/")

        # Separate the anchor fragment if present.
        # Example: "folder/SomeClass.html#methods"
        if "#" in normalized:
            path_part, frag = normalized.split("#", 1)
            has_fragment = True
        else:
            path_part = normalized
            frag = ""
            has_fragment = False

        # If the path starts with "{folder}/", remove that prefix exactly once.
        if path_part.startswith(prefix):
            path_part = path_part[len(prefix):]

            # Reconstruct the final href, preserving the anchor if it existed.
            new_href = path_part
            if has_fragment:
                new_href = f"{new_href}#{frag}"

            # Perform the update only if the href actually changed.
            if new_href != href:
                a["href"] = new_href
                changed += 1

    # Write updated HTML back to the file only if modifications occurred.
    if changed:
        html_path.write_text(str(soup), encoding="utf-8")

    return changed
