# Copyright (C) 2026 GoodData Corporation

"""Best-effort Git history inference for onboarding templates."""

from __future__ import annotations

import re
import subprocess
from collections import Counter
from dataclasses import dataclass
from pathlib import Path

_TYPE_RE = re.compile(r"^(?P<type>[a-z]+)(?:\((?P<scope>[^)]+)\))?:\s+")
_TICKET_RE = re.compile(r"\b(?P<prefix>[A-Z][A-Z0-9]{1,9})-\d+\b")
_RISK_RE = re.compile(r"^risk:\s*(?P<risk>[a-z0-9_-]+)\s*$", flags=re.IGNORECASE | re.MULTILINE)


@dataclass(frozen=True, slots=True)
class TemplateHints:
    has_history: bool
    suggested_type: str
    suggested_scope: str
    ticket_prefix: str
    suggested_risk: str
    uses_co_authored_by: bool
    pr_title_often_has_number_suffix: bool


def infer_template_hints(workspace_root: Path) -> TemplateHints:
    records = _read_recent_commit_records(workspace_root)
    if not records:
        return TemplateHints(
            has_history=False,
            suggested_type="chore",
            suggested_scope="",
            ticket_prefix="",
            suggested_risk="nonprod",
            uses_co_authored_by=False,
            pr_title_often_has_number_suffix=False,
        )

    type_counter: Counter[str] = Counter()
    scope_counter: Counter[str] = Counter()
    ticket_prefix_counter: Counter[str] = Counter()
    risk_counter: Counter[str] = Counter()
    uses_co_authored_by = False
    pr_title_suffix_counter = 0

    for subject, body in records:
        subject_stripped = subject.strip()
        match = _TYPE_RE.match(subject_stripped)
        if match:
            type_counter.update([match.group("type").lower()])
            scope_value = (match.group("scope") or "").strip()
            if scope_value:
                scope_counter.update([scope_value])

        text = f"{subject}\n{body}"
        for ticket_match in _TICKET_RE.finditer(text):
            ticket_prefix_counter.update([ticket_match.group("prefix").upper()])

        for risk_match in _RISK_RE.finditer(body):
            risk_counter.update([risk_match.group("risk").lower()])

        if "co-authored-by:" in text.lower():
            uses_co_authored_by = True

        if re.search(r"\(#\d+\)\s*$", subject_stripped):
            pr_title_suffix_counter += 1

    return TemplateHints(
        has_history=True,
        suggested_type=_most_common(type_counter, fallback="chore"),
        suggested_scope=_most_common(scope_counter, fallback=""),
        ticket_prefix=_most_common(ticket_prefix_counter, fallback=""),
        suggested_risk=_most_common(risk_counter, fallback="nonprod"),
        uses_co_authored_by=uses_co_authored_by,
        pr_title_often_has_number_suffix=pr_title_suffix_counter >= 2,
    )


def _read_recent_commit_records(workspace_root: Path) -> list[tuple[str, str]]:
    cmd = ["git", "-C", str(workspace_root), "log", "--format=%s%x00%b%x1e", "-n", "200"]
    try:
        result = subprocess.run(cmd, check=False, capture_output=True, text=True)
    except OSError:
        return []
    if result.returncode != 0:
        return []

    records: list[tuple[str, str]] = []
    for raw in result.stdout.split("\x1e"):
        cleaned = raw.strip()
        if not cleaned or "\x00" not in cleaned:
            continue
        subject, body = cleaned.split("\x00", 1)
        records.append((subject.strip(), body.strip()))
    return records


def _most_common(counter: Counter[str], *, fallback: str) -> str:
    if not counter:
        return fallback
    value, _count = counter.most_common(1)[0]
    return value
