"""
Extract fenced code blocks from Markdown.
Handles the special ``language:filename`` format.
"""

import re

_FENCE_RE = re.compile(
    r"```(\S*?)(?::(\S+?))?\s*?\n(.*?)```",
    re.DOTALL,
)

_LANG_EXT = {
    "python": "py", "javascript": "js", "typescript": "ts",
    "csharp": "cs", "cpp": "cpp", "c": "c", "java": "java",
    "ruby": "rb", "go": "go", "rust": "rs", "swift": "swift",
    "kotlin": "kt", "php": "php", "html": "html", "css": "css",
    "scss": "scss", "json": "json", "yaml": "yaml", "yml": "yaml",
    "xml": "xml", "sql": "sql", "bash": "sh", "shell": "sh",
    "sh": "sh", "dockerfile": "Dockerfile", "lua": "lua",
    "dart": "dart", "tsx": "tsx", "jsx": "jsx", "vue": "vue",
    "svelte": "svelte", "toml": "toml", "ini": "ini",
    "markdown": "md", "md": "md", "txt": "txt", "text": "txt",
    "glsl": "glsl", "hlsl": "hlsl", "gdscript": "gd",
}


def extract_code_blocks(markdown: str) -> list[dict]:
    """
    Returns list of dicts: {language, filename, code}
    """
    blocks: list[dict] = []
    counter: dict[str, int] = {}

    for m in _FENCE_RE.finditer(markdown):
        lang = (m.group(1) or "text").lower()
        explicit_filename = m.group(2)          # may be None
        code = m.group(3).strip()

        if not code:
            continue

        if explicit_filename:
            filename = explicit_filename
        else:
            ext = _LANG_EXT.get(lang, lang or "txt")
            counter[ext] = counter.get(ext, 0) + 1
            n = counter[ext]
            filename = f"code_{n}.{ext}" if n > 1 else f"code.{ext}"

        blocks.append({
            "language": lang,
            "filename": filename,
            "code": code,
        })

    return blocks