# retoor <retoor@molodetz.nl>
from __future__ import annotations

LANGUAGE_BY_EXTENSION: dict[str, str] = {
    ".py": "python",
    ".pyw": "python",
    ".js": "javascript",
    ".mjs": "javascript",
    ".cjs": "javascript",
    ".jsx": "javascript",
    ".ts": "typescript",
    ".tsx": "typescript",
    ".html": "html",
    ".htm": "html",
    ".css": "css",
    ".scss": "css",
    ".less": "css",
    ".php": "php",
    ".go": "go",
    ".java": "java",
    ".kt": "java",
    ".c": "c",
    ".h": "c",
    ".cpp": "cpp",
    ".cc": "cpp",
    ".hpp": "cpp",
    ".cs": "csharp",
    ".rb": "ruby",
    ".rs": "rust",
    ".sh": "shell",
    ".bash": "shell",
    ".lua": "lua",
    ".sql": "sql",
    ".md": "markdown",
    ".rst": "markdown",
    ".txt": "text",
    ".json": "json",
    ".yaml": "yaml",
    ".yml": "yaml",
    ".toml": "toml",
    ".xml": "xml",
    ".vue": "javascript",
    ".svelte": "javascript",
}

CODE_LANGUAGES: frozenset[str] = frozenset(
    {
        "python",
        "javascript",
        "typescript",
        "php",
        "go",
        "java",
        "c",
        "cpp",
        "csharp",
        "ruby",
        "rust",
        "shell",
        "lua",
        "sql",
        "html",
        "css",
    }
)

DOCUMENT_LANGUAGES: frozenset[str] = frozenset({"markdown", "text"})

LINE_COMMENT_PREFIXES: dict[str, tuple[str, ...]] = {
    "python": ("#",),
    "shell": ("#",),
    "ruby": ("#",),
    "yaml": ("#",),
    "toml": ("#",),
    "javascript": ("//",),
    "typescript": ("//",),
    "php": ("//", "#"),
    "go": ("//",),
    "java": ("//",),
    "c": ("//",),
    "cpp": ("//",),
    "csharp": ("//",),
    "rust": ("//",),
    "sql": ("--",),
    "lua": ("--",),
}

BLOCK_COMMENT_LANGUAGES: frozenset[str] = frozenset(
    {"javascript", "typescript", "php", "go", "java", "c", "cpp", "csharp", "rust", "css"}
)


def language_for(filename: str) -> str:
    lowered = filename.lower()
    for extension, language in LANGUAGE_BY_EXTENSION.items():
        if lowered.endswith(extension):
            return language
    return "unknown"


def extract_comments(language: str, lines: list[str]) -> list[tuple[int, str]]:
    comments: list[tuple[int, str]] = []
    prefixes = LINE_COMMENT_PREFIXES.get(language, ())
    in_block = False
    block_open, block_close = ("/*", "*/") if language in BLOCK_COMMENT_LANGUAGES or language == "css" else ("", "")
    if language == "html":
        block_open, block_close = "<!--", "-->"
    for number, raw in enumerate(lines, start=1):
        stripped = raw.strip()
        if in_block:
            comments.append((number, stripped.replace(block_close, "").strip()))
            if block_close and block_close in stripped:
                in_block = False
            continue
        if block_open and block_open in stripped:
            fragment = stripped.split(block_open, 1)[1]
            comments.append((number, fragment.replace(block_close, "").strip()))
            if block_close not in fragment:
                in_block = True
            continue
        for prefix in prefixes:
            if stripped.startswith(prefix):
                comments.append((number, stripped[len(prefix):].strip()))
                break
            marker = f" {prefix}"
            if marker in raw and not _inside_string(raw, raw.index(marker)):
                comments.append((number, raw.split(marker, 1)[1].strip()))
                break
    return comments


def _inside_string(line: str, position: int) -> bool:
    double = line.count('"', 0, position) % 2 == 1
    single = line.count("'", 0, position) % 2 == 1
    return double or single
