"""
Output sanitizer.
Strips markdown fences, natural-language preambles/epilogues, and other
non-code artifacts that the model may produce despite instructions.
"""
import re


def sanitize_code_output(text: str, target_lang_hint: str = "") -> str:
    """
    Clean model output to extract pure source code.

    Steps:
      1. Strip leading/trailing whitespace.
      2. Remove markdown code fences (```lang ... ```), possibly nested.
      3. Remove natural-language preamble lines before the first code line.
      4. Remove natural-language epilogue after the last code line.
      5. Trim trailing whitespace on each line, keep one trailing newline.
    """
    text = text.strip()
    if not text:
        return ""

    # --- Step 2: Remove markdown fences ---
    text = _strip_all_fences(text)

    # --- Step 3 & 4: Remove preamble / epilogue ---
    text = _strip_preamble_epilogue(text, target_lang_hint)

    # --- Step 5: Normalize trailing whitespace ---
    lines = [line.rstrip() for line in text.splitlines()]
    # Remove leading/trailing empty lines
    while lines and not lines[0]:
        lines.pop(0)
    while lines and not lines[-1]:
        lines.pop()

    return "\n".join(lines) + "\n" if lines else ""


def _strip_all_fences(text: str) -> str:
    """Remove all markdown code fences, handling nested/multiple blocks."""
    # Pattern: ```optional_lang\n ... \n```
    # Use non-greedy to handle multiple blocks
    result = re.sub(
        r"```[\w+#\-./]*\s*\n(.*?)```",
        r"\1",
        text,
        flags=re.DOTALL,
    )
    # Handle case where entire text is a single fenced block (no trailing newline before ```)
    result = re.sub(r"^```[\w+#\-./]*\s*\n?", "", result)
    result = re.sub(r"\n?```\s*$", "", result)
    return result.strip()


# Patterns that indicate natural language, not code
_NL_PATTERNS = [
    re.compile(r"^(Here('s| is)|Below is|The following|This (is|code)|I('ve| have)|Note:|Let me|Sure|Certainly|Of course)", re.IGNORECASE),
    re.compile(r"^(以下|これは|変換|コード|次の|上記|注意|説明)", re.IGNORECASE),
    re.compile(r"^(Aquí|A continuación|El siguiente|Este código)", re.IGNORECASE),
    re.compile(r"^(Voici|Le code|Ci-dessous)", re.IGNORECASE),
    re.compile(r"^(Hier ist|Der folgende|Das ist)", re.IGNORECASE),
    re.compile(r"^(다음은|이것은|코드|변환)", re.IGNORECASE),
    re.compile(r"^(下面是|以下是|这是|代码)", re.IGNORECASE),
]

# Patterns for epilogue detection
_EPILOGUE_PATTERNS = [
    re.compile(r"^(Key (changes|differences|notes)|Notes?:|Explanation:|This (converts|translates)|The (main|key) (change|difference))", re.IGNORECASE),
    re.compile(r"^(主な(変更|違い)|注意|説明|ポイント|補足)", re.IGNORECASE),
    re.compile(r"^(---+\s*$)"),
]


def _is_natural_language_line(line: str) -> bool:
    """Check if a line looks like natural language, not code."""
    stripped = line.strip()
    if not stripped:
        return False
    return any(p.search(stripped) for p in _NL_PATTERNS)


def _is_epilogue_line(line: str) -> bool:
    """Check if a line looks like the start of an epilogue."""
    stripped = line.strip()
    if not stripped:
        return False
    return any(p.search(stripped) for p in _EPILOGUE_PATTERNS)


def _strip_preamble_epilogue(text: str, target_lang_hint: str = "") -> str:
    """Remove natural language before/after the actual code."""
    lines = text.splitlines()
    if not lines:
        return text

    # Strip preamble: remove leading NL lines (up to 5 lines max)
    start = 0
    for i, line in enumerate(lines[:5]):
        if _is_natural_language_line(line):
            start = i + 1
        elif not line.strip():
            # Skip empty lines between NL preamble lines
            if start > 0:
                start = i + 1
        else:
            break

    # Strip epilogue: scan forward from start looking for epilogue markers.
    # Once an epilogue marker is found, everything from that line onward is removed.
    end = len(lines)
    for i in range(start, len(lines)):
        if _is_epilogue_line(lines[i]):
            end = i
            break

    # Also trim trailing NL lines (natural language after last code line)
    while end > start and not lines[end - 1].strip():
        end -= 1
    while end > start and _is_natural_language_line(lines[end - 1]):
        end -= 1

    return "\n".join(lines[start:end])
