"""Markdown preprocessor ("Style Guard") for StyloBridge.

Normalizes markdown before Pandoc conversion to ensure consistent,
enterprise-quality DOCX output regardless of how the AI or user
wrote the source markdown.
"""

import os
import re
import stat
import tempfile
from pathlib import Path


def preprocess_markdown_content(content: str) -> str:
    """Clean and normalize markdown content for optimal Pandoc conversion.

    Args:
        content: Raw markdown text.

    Returns:
        Cleaned markdown text ready for Pandoc.
    """
    lines = content.split("\n")
    lines = _normalize_bullets(lines)
    lines = _normalize_whitespace(lines)
    lines = _normalize_tables(lines)
    lines = _inject_table_captions(lines)
    return "\n".join(lines)


def preprocess_markdown(input_path: str) -> str:
    """Clean and normalize a markdown file for optimal Pandoc conversion.

    Args:
        input_path: Path to the source markdown file.

    Returns:
        Path to a temporary cleaned markdown file.
        Caller is responsible for cleanup.
    """
    content = Path(input_path).read_text(encoding="utf-8")
    cleaned = preprocess_markdown_content(content)

    fd, tmp_path = tempfile.mkstemp(suffix=".md")
    with os.fdopen(fd, "w", encoding="utf-8") as tmp:
        tmp.write(cleaned)
    os.chmod(tmp_path, stat.S_IRUSR | stat.S_IWUSR)  # 0o600
    return tmp_path


def _normalize_bullets(lines: list[str]) -> list[str]:
    """Standardize nested bullet indentation to exactly 4 spaces per level."""
    result = []
    for line in lines:
        match = re.match(r"^(\s*)([-*+])\s", line)
        if match:
            raw_indent = match.group(1)
            bullet_char = match.group(2)
            # Calculate nesting level from any indentation style
            if raw_indent:
                # Count indent: tabs = 1 level, spaces grouped by 2-4 = 1 level
                expanded = raw_indent.replace("\t", "    ")
                level = len(expanded) // 2  # Normalize any 2+ space indent
                if level == 0 and len(expanded) > 0:
                    level = 1
            else:
                level = 0
            normalized_indent = "    " * level
            rest = line[match.end():]
            result.append(f"{normalized_indent}{bullet_char} {rest}")
        else:
            result.append(line)
    return result


def _normalize_whitespace(lines: list[str]) -> list[str]:
    """Ensure blank lines around headings, tables, and code blocks.

    Pandoc requires blank lines before/after these elements for
    correct parsing.
    """
    result = []
    for i, line in enumerate(lines):
        stripped = line.strip()

        # Before headings: ensure blank line
        if stripped.startswith("#") and i > 0:
            if result and result[-1].strip() != "":
                result.append("")

        result.append(line)

        # After headings: ensure blank line
        if stripped.startswith("#") and i < len(lines) - 1:
            next_line = lines[i + 1].strip()
            if next_line != "":
                result.append("")

        # Before code blocks: ensure blank line
        if stripped.startswith("```") and i > 0:
            # Check if we already added a blank line
            if len(result) >= 2 and result[-2].strip() != "" and not result[-2].strip().startswith("#"):
                pass  # Already handled by heading logic or naturally present

    return result


def _normalize_tables(lines: list[str]) -> list[str]:
    """Normalize pipe table alignment and column separators."""
    result = []
    for line in lines:
        stripped = line.strip()
        if _is_table_row(stripped):
            # Split on pipes, ignoring the empty first/last from leading/trailing |
            inner = stripped[1:-1]  # Remove outer pipes
            cells = inner.split("|")
            normalized_cells = [f" {cell.strip()} " for cell in cells]
            result.append("|" + "|".join(normalized_cells) + "|")
        else:
            result.append(line)
    return result


def _is_table_row(line: str) -> bool:
    """Check if a line is a markdown pipe table row."""
    stripped = line.strip()
    if not stripped.startswith("|") or not stripped.endswith("|"):
        return False
    # Must have at least one internal pipe
    inner = stripped[1:-1]
    return "|" in inner


def _is_separator_row(line: str) -> bool:
    """Check if a line is a table separator row (|---|---|)."""
    stripped = line.strip()
    if not _is_table_row(stripped):
        return False
    inner = stripped.strip("|")
    cells = inner.split("|")
    return all(re.match(r"^\s*:?-+:?\s*$", cell) for cell in cells)


def _inject_table_captions(lines: list[str]) -> list[str]:
    """Scan for tables and inject Pandoc Table: [Caption] syntax.

    Uses a stateful counter for sequential numbering. Looks back up
    to 2 lines (handling AI-generated blank buffer lines) to find
    heading or bold text to use as caption source.

    Overwrites existing table numbers to maintain sequential consistency.
    """
    result = []
    table_counter = 0

    i = 0
    while i < len(lines):
        stripped = lines[i].strip()

        # Detect start of a table (first row with pipes, followed by separator)
        if _is_table_row(stripped) and not _is_separator_row(stripped):
            # Check if next line is a separator row (confirming this is a real table)
            if i + 1 < len(lines) and _is_separator_row(lines[i + 1].strip()):
                table_counter += 1
                caption = _extract_caption(result, table_counter)

                if caption:
                    # Insert Pandoc caption before the table
                    result.append(f"Table: {caption}")
                    result.append("")

        result.append(lines[i])
        i += 1

    return result


def _extract_caption(preceding_lines: list[str], table_number: int) -> str | None:
    """Extract a caption from preceding context.

    Looks back 1-2 lines. If line[-1] is blank, checks line[-2].
    Derives caption from headings (#) or bold text (**).
    Overwrites any existing "Table N:" numbering for sequential consistency.
    """
    if not preceding_lines:
        return None

    def _clean_caption_text(text: str) -> str:
        """Strip markdown formatting and existing table numbers."""
        # Remove heading markers
        text = re.sub(r"^#+\s*", "", text)
        # Remove bold markers
        text = text.strip("*").strip()
        # Remove existing "Table N:" prefix for re-numbering
        text = re.sub(r"^Table\s+\d+\s*:\s*", "", text, flags=re.IGNORECASE)
        return text.strip()

    # Check last line
    last = preceding_lines[-1].strip()
    if last.startswith("#") or last.startswith("**"):
        caption_text = _clean_caption_text(last)
        if caption_text:
            return f"Table {table_number}: {caption_text}"

    # If last line is blank, check 2 lines back (AI buffer line pattern)
    if last == "" and len(preceding_lines) >= 2:
        second_last = preceding_lines[-2].strip()
        if second_last.startswith("#") or second_last.startswith("**"):
            caption_text = _clean_caption_text(second_last)
            if caption_text:
                return f"Table {table_number}: {caption_text}"

    return None
