"""Synchronize documentation files from submodules to main docs directory.

This script automatically discovers and copies documentation files from git
submodules to the main documentation tree. It parses .gitmodules to find all
submodules and syncs their docs directories.

Additionally validates that all synced files are referenced in mkdocs.yml.
"""

import configparser
import re
import shutil
from pathlib import Path


def parse_gitmodules(repo_root: Path) -> list[str]:
    """Parse .gitmodules to get all submodule paths.

    Args:
        repo_root: Root directory of the git repository

    Returns:
        List of submodule paths (e.g., ['data', 'authentication'])
    """
    gitmodules_path = repo_root / ".gitmodules"
    if not gitmodules_path.exists():
        print("Warning: .gitmodules not found")
        return []

    config = configparser.ConfigParser()
    config.read(gitmodules_path)

    submodules = []
    for section in config.sections():
        if section.startswith("submodule"):
            path = config.get(section, "path", fallback=None)
            if path:
                submodules.append(path)

    return submodules


def discover_docs_tree(submodule_docs: Path, base_path: Path = Path()) -> list[str]:
    """Recursively discover all .md files in a directory tree.

    Args:
        submodule_docs: Root directory to search (e.g., data/docs)
        base_path: Current relative path (for recursion)

    Returns:
        List of file paths relative to submodule_docs (e.g., ['api/client.md'])
    """
    discovered = []
    current_dir = submodule_docs / base_path

    if not current_dir.exists():
        return []

    for item in sorted(current_dir.iterdir()):
        relative_path = base_path / item.name

        if item.is_file() and item.suffix == ".md":
            discovered.append(str(relative_path.as_posix()))
        elif item.is_dir():
            # Recursively discover in subdirectories
            discovered.extend(discover_docs_tree(submodule_docs, relative_path))

    return discovered


def find_docs_directory(base_dir: Path, submodule_path: str) -> Path | None:
    """Find the docs directory for a submodule.

    Tries multiple common locations:
    - <submodule>/docs (standard)
    - <submodule>/src/python-client/docs (nested structure)

    Args:
        base_dir: Repository root directory
        submodule_path: Path to submodule (e.g., 'data', 'automation')

    Returns:
        Path to docs directory if found, None otherwise
    """
    submodule_root = base_dir / submodule_path

    # Standard location
    standard_docs = submodule_root / "docs"
    if standard_docs.exists():
        return standard_docs

    # Nested location (e.g., automation/src/python-client/docs)
    nested_docs = submodule_root / "src" / "python-client" / "docs"
    if nested_docs.exists():
        return nested_docs

    return None


def clean_target_directory(target_docs: Path, keep_files: set[str]) -> None:
    """Remove files from target directory that are not in keep_files set.

    Args:
        target_docs: Target directory to clean
        keep_files: Set of file paths (relative to target_docs) to keep
    """
    if not target_docs.exists():
        return

    removed_count = 0
    for item in target_docs.rglob("*.md"):
        relative_path = item.relative_to(target_docs).as_posix()
        if relative_path not in keep_files:
            item.unlink()
            print(f"Removed outdated: {target_docs.name}/{relative_path}")
            removed_count += 1

    if removed_count > 0:
        print(f"Removed {removed_count} outdated file(s)")


def sync_submodule_docs(submodule_path: str) -> list[str]:
    """Synchronize all documentation files from a submodule to main docs.

    Automatically discovers all .md files in the submodule's docs directory
    and copies them while preserving directory structure. Removes outdated
    files that no longer exist in the submodule.

    Args:
        submodule_path: Path to submodule (e.g., 'data', 'authentication')

    Returns:
        List of synced file paths relative to docs/ directory
    """
    base_dir = Path(__file__).parent.parent
    submodule_docs = find_docs_directory(base_dir, submodule_path)
    target_docs = base_dir / "docs" / submodule_path

    if submodule_docs is None:
        print(f"Warning: Submodule docs directory not found for: {submodule_path}")
        return []

    # Discover all .md files in submodule docs
    discovered_files = discover_docs_tree(submodule_docs)

    if not discovered_files:
        print(f"No documentation files found in {submodule_path}")
        return []

    target_docs.mkdir(parents=True, exist_ok=True)

    # Clean outdated files before syncing
    clean_target_directory(target_docs, set(discovered_files))

    synced_files = []
    for file_path in discovered_files:
        source_file = submodule_docs / file_path
        target_file = target_docs / file_path

        # Create target directory if needed
        target_file.parent.mkdir(parents=True, exist_ok=True)

        # Copy file
        shutil.copy2(source_file, target_file)
        print(f"Synced: {submodule_path}/{file_path}")
        synced_files.append(f"{submodule_path}/{file_path}")

    print(f"Synced {len(synced_files)} file(s) for {submodule_path}")
    return synced_files


def extract_nav_files(mkdocs_path: Path) -> set[str]:
    """Extract all file paths from mkdocs.yml nav section.

    Uses regex-based extraction to avoid YAML parsing issues with
    mkdocs.yml Python tags.

    Args:
        mkdocs_path: Path to mkdocs.yml

    Returns:
        Set of file paths found in nav section
    """
    if not mkdocs_path.exists():
        print(f"Warning: mkdocs.yml not found: {mkdocs_path}")
        return set()

    try:
        with open(mkdocs_path, encoding="utf-8") as f:
            content = f.read()

        # Extract nav section (from "nav:" to next top-level key or EOF)
        nav_match = re.search(r"^nav:\s*\n(.*?)(?=^\S|\Z)", 
                                content, re.MULTILINE | re.DOTALL)
        if not nav_match:
            return set()

        nav_section = nav_match.group(1)

        # Find all .md file references in nav section
        # Pattern: captures "path/to/file.md" after ": "
        md_files = re.findall(r":\s+([a-zA-Z0-9_/.-]+\.md)", nav_section)

        return set(md_files)
    except Exception as e:
        print(f"Warning: Could not parse mkdocs.yml: {e}")
        return set()


def validate_nav_references(
    synced_files: list[str], mkdocs_path: Path
) -> None:
    """Validate that synced files are referenced in mkdocs.yml nav.

    Args:
        synced_files: List of synced file paths (relative to docs/)
        mkdocs_path: Path to mkdocs.yml
    """
    nav_files = extract_nav_files(mkdocs_path)

    missing_in_nav = [f for f in synced_files if f not in nav_files]

    if missing_in_nav:
        print(f"\n{'=' * 70}")
        print("[!] Warning: The following synced files are NOT in mkdocs.yml:")
        print(f"{'=' * 70}")
        for file in sorted(missing_in_nav):
            print(f"   - {file}")
        print("\nConsider adding them to the 'nav' section in mkdocs.yml")
        print(f"{'=' * 70}\n")
    else:
        print("\n[OK] All synced files are referenced in mkdocs.yml")


def sync_all_docs() -> None:
    """Synchronize all submodule documentation files.

    Automatically discovers all submodules from .gitmodules and syncs
    all their documentation files.
    """
    base_dir = Path(__file__).parent.parent
    mkdocs_path = base_dir / "mkdocs.yml"

    # Discover all submodules from .gitmodules
    submodules = parse_gitmodules(base_dir)

    if not submodules:
        print("No submodules found in .gitmodules")
        return

    print(f"Discovered {len(submodules)} submodule(s): {', '.join(submodules)}\n")

    # Sync all submodules
    all_synced_files = []
    for submodule in submodules:
        synced = sync_submodule_docs(submodule)
        all_synced_files.extend(synced)

    # Validate nav references
    validate_nav_references(all_synced_files, mkdocs_path)


if __name__ == "__main__":
    sync_all_docs()
