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

import re

from devplacepy.services.jobs.isslop.analysis.signals import (
    AXIS_ORIGIN,
    SEVERITY_MEDIUM,
    SEVERITY_STRONG,
    SEVERITY_WEAK,
    FileContext,
    Signal,
)

HTML_SCAFFOLD_PATTERNS: tuple[tuple[re.Pattern[str], str, str], ...] = (
    (re.compile(r"Generated by create next app", re.IGNORECASE), "Untouched create-next-app metadata", SEVERITY_STRONG),
    (re.compile(r"<title>\s*Create Next App\s*</title>", re.IGNORECASE), "Default Create Next App title", SEVERITY_STRONG),
    (re.compile(r"<title>\s*(Vite \+ React|Vite App|React App)\s*</title>", re.IGNORECASE), "Default Vite/CRA title", SEVERITY_STRONG),
    (re.compile(r"You need to enable JavaScript to run this app", re.IGNORECASE), "Create React App noscript boilerplate", SEVERITY_STRONG),
    (re.compile(r"/vite\.svg|src=[\"']/?vite\.svg", re.IGNORECASE), "Default Vite logo asset", SEVERITY_MEDIUM),
    (re.compile(r"<div\s+id=[\"']root[\"']\s*>\s*</div>", re.IGNORECASE), "Empty CRA/Vite root mount div", SEVERITY_MEDIUM),
    (re.compile(r"<div\s+id=[\"']__next[\"']", re.IGNORECASE), "Next.js hydration root", SEVERITY_WEAK),
    (re.compile(r"src=[\"']/src/main\.(jsx|tsx)[\"']", re.IGNORECASE), "Default Vite entry module", SEVERITY_MEDIUM),
    (re.compile(r"Edit <code>src/App", re.IGNORECASE), "Untouched CRA starter copy", SEVERITY_STRONG),
    (re.compile(r"Save to reload", re.IGNORECASE), "Untouched Vite/CRA starter copy", SEVERITY_STRONG),
    (re.compile(r"content=[\"']Web site created using create-react-app", re.IGNORECASE), "CRA description meta", SEVERITY_STRONG),
    (re.compile(r"%PUBLIC_URL%", re.IGNORECASE), "Unrendered CRA template token", SEVERITY_STRONG),
    (re.compile(r"__NEXT_DATA__|self\.__next_f", re.IGNORECASE), "Next.js runtime payload", SEVERITY_WEAK),
    (re.compile(r"<meta[^>]+name=[\"']generator[\"'][^>]+(gatsby|hugo|jekyll|astro|next\.js|nuxt|docusaurus)", re.IGNORECASE), "Static-site generator meta", SEVERITY_WEAK),
)

PY_DOCSTRING_TRIVIAL_PATTERN = re.compile(
    r"def\s+\w+\([^)]*\)\s*(?:->[^\n:]+)?:\s*\n\s*(?:\"\"\"|''')[^\n]{5,80}(?:\"\"\"|''')\s*\n\s*return\b",
    re.MULTILINE,
)
PY_VERBOSE_NAME_PATTERN = re.compile(r"\b[a-z]+(?:_[a-z]+){4,}\b\s*=")
PY_ERROR_PRINT_PATTERN = re.compile(
    r"except\s+\w*(?:Exception|Error)?\s*(?:as\s+(\w+))?\s*:\s*\n\s*print\(\s*f?[\"'](?:an?\s+)?error", re.IGNORECASE
)
PY_MAIN_GUARD_PATTERN = re.compile(r"^if\s+__name__\s*==\s*[\"']__main__[\"']\s*:", re.MULTILINE)
PY_TYPE_HINT_PATTERN = re.compile(r"def\s+\w+\([^)]*:\s*\w+[^)]*\)\s*->\s*\w+")
PY_FULL_DOCSTRING_PATTERN = re.compile(r"def\s+\w+[^:]*:\s*\n\s*(?:\"\"\"|''')")
PY_LOGGING_FSTRING_PATTERN = re.compile(r"logging\.(info|debug|warning|error)\(\s*f[\"']")

VERBOSE_NAME_THRESHOLD: int = 2
TRIVIAL_DOCSTRING_THRESHOLD: int = 2
TEXTBOOK_MIN_FUNCTIONS: int = 5


def _line_of(text: str, position: int) -> int:
    return text.count("\n", 0, position) + 1


def _html_scaffold_signals(context: FileContext) -> list[Signal]:
    findings: list[Signal] = []
    text = context.text
    for pattern, title, severity in HTML_SCAFFOLD_PATTERNS:
        match = pattern.search(text)
        if match:
            weight = 4.0 if severity == SEVERITY_STRONG else (2.0 if severity == SEVERITY_MEDIUM else 0.5)
            findings.append(
                Signal("FRAMEWORK_SCAFFOLD", f"Framework scaffold artifact: {title}", severity, AXIS_ORIGIN, weight, _line_of(text, match.start()), match.group(0)[:100])
            )
    return findings


def _python_structure_signals(context: FileContext) -> list[Signal]:
    findings: list[Signal] = []
    text = context.text
    metrics = context.metrics

    trivial = PY_DOCSTRING_TRIVIAL_PATTERN.findall(text)
    if len(trivial) >= TRIVIAL_DOCSTRING_THRESHOLD:
        match = PY_DOCSTRING_TRIVIAL_PATTERN.search(text)
        findings.append(
            Signal(
                "TRIVIAL_DOCSTRINGS",
                f"{len(trivial)} trivial functions with textbook docstrings",
                SEVERITY_MEDIUM,
                AXIS_ORIGIN,
                2.0,
                _line_of(text, match.start()) if match else 1,
                "over-documented one-line functions",
            )
        )

    verbose = PY_VERBOSE_NAME_PATTERN.findall(text)
    if len(verbose) >= VERBOSE_NAME_THRESHOLD:
        match = PY_VERBOSE_NAME_PATTERN.search(text)
        findings.append(
            Signal(
                "VERBOSE_TEXTBOOK_NAMES",
                f"{len(verbose)} extremely verbose textbook variable names",
                SEVERITY_MEDIUM,
                AXIS_ORIGIN,
                2.0,
                _line_of(text, match.start()) if match else 1,
                match.group(0).strip()[:80] if match else "",
            )
        )

    error_print = PY_ERROR_PRINT_PATTERN.search(text)
    if error_print:
        findings.append(
            Signal(
                "GENERIC_ERROR_PRINT",
                "Textbook 'except: print(f\"Error: {e}\")' handling",
                SEVERITY_MEDIUM,
                AXIS_ORIGIN,
                2.0,
                _line_of(text, error_print.start()),
                error_print.group(0).strip()[:80],
            )
        )

    if metrics is not None and metrics.function_count >= TEXTBOOK_MIN_FUNCTIONS:
        typed = len(PY_TYPE_HINT_PATTERN.findall(text))
        documented = len(PY_FULL_DOCSTRING_PATTERN.findall(text))
        has_main_guard = bool(PY_MAIN_GUARD_PATTERN.search(text))
        logging_fstring = bool(PY_LOGGING_FSTRING_PATTERN.search(text))
        markers = sum(
            [
                typed >= max(3, metrics.function_count // 2),
                documented >= metrics.function_count,
                has_main_guard,
                logging_fstring,
            ]
        )
        if markers >= 3:
            findings.append(
                Signal(
                    "TEXTBOOK_STRUCTURE",
                    "Uniformly textbook structure: full type hints, docstring on every function, main guard",
                    SEVERITY_MEDIUM,
                    AXIS_ORIGIN,
                    3.0,
                    1,
                    f"typed={typed}, docstrings={documented}, main_guard={has_main_guard}",
                )
            )
    return findings


def detect_scaffolds(context: FileContext) -> list[Signal]:
    if context.language == "html":
        return _html_scaffold_signals(context)
    if context.language == "python":
        return _python_structure_signals(context)
    return []
