# aider-watch-client parsers | 2026-04-20 @ Asia/Taipei
"""從 aider stdout / chat_history.md / git diff 抽事件資訊。"""
from __future__ import annotations
import re
import subprocess
from pathlib import Path

_BANNER_MODEL = re.compile(r"^\s*Model:\s*(\S+)", re.MULTILINE)
_BANNER_VER = re.compile(r"^\s*Aider v([\d\.]+)", re.MULTILINE)
_TOKENS_LINE = re.compile(
    r"Tokens:\s+([\d\.]+)([km]?)\s+sent,\s+([\d\.]+)([km]?)\s+received",
    re.IGNORECASE,
)


def _parse_num(n: str, suffix: str) -> int:
    v = float(n)
    if suffix.lower() == "k":
        v *= 1000
    elif suffix.lower() == "m":
        v *= 1_000_000
    return int(v)


def parse_stdout_banner(stdout: str) -> dict:
    m_model = _BANNER_MODEL.search(stdout)
    m_ver = _BANNER_VER.search(stdout)
    return {
        "model": m_model.group(1) if m_model else None,
        "cli_version": m_ver.group(1) if m_ver else None,
    }


def parse_chat_history(md: str) -> dict:
    total_sent = 0
    total_recv = 0
    for m in _TOKENS_LINE.finditer(md):
        total_sent += _parse_num(m.group(1), m.group(2))
        total_recv += _parse_num(m.group(3), m.group(4))
    return {"tokens_sent": total_sent, "tokens_received": total_recv,
            "file_edits": []}


def parse_git_diff_stat(diff_stat: str) -> list[dict]:
    out = []
    for line in diff_stat.strip().splitlines():
        parts = line.split("\t")
        if len(parts) != 3:
            continue
        add, dele, path = parts
        try:
            a = int(add) if add != "-" else 0
            d = int(dele) if dele != "-" else 0
        except ValueError:
            continue
        out.append({"path": path, "lines_added": a, "lines_deleted": d,
                    "is_new_file": d == 0 and a > 0})
    return out


def git_numstat(cwd: Path, pre_sha: str, post_sha: str = "HEAD") -> list[dict]:
    try:
        r = subprocess.run(
            ["git", "-C", str(cwd), "diff", "--numstat", pre_sha, post_sha],
            capture_output=True, text=True, timeout=10)
        if r.returncode != 0:
            return []
        return parse_git_diff_stat(r.stdout)
    except Exception:
        return []


def git_diff_head(cwd: Path, path: str, pre_sha: str, n: int = 3) -> list[str]:
    try:
        r = subprocess.run(
            ["git", "-C", str(cwd), "diff", "-U0", pre_sha, "--", path],
            capture_output=True, text=True, timeout=5)
        picks = []
        for l in r.stdout.splitlines():
            if l.startswith("+++") or l.startswith("---"):
                continue
            if l.startswith("@@") or l.startswith("+") or l.startswith("-"):
                picks.append(l)
                if len(picks) >= n:
                    break
        return picks
    except Exception:
        return []
