#!/usr/bin/env python3
import argparse
import datetime as dt
import re
import subprocess
import sys
from collections import defaultdict


CHECKOUT_RE = re.compile(r"checkout: moving from (.+) to (.+)")
TICKET_BRANCH_RE = re.compile(r"^(T\d{5})_[A-Za-z0-9_\-]+$")


def run_git(args):
    proc = subprocess.run(["git"] + args, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or "Error ejecutando git")
    return proc.stdout


def parse_args():
    parser = argparse.ArgumentParser(
        description="Genera resumen diario de bitacora por ticket/rama."
    )
    parser.add_argument(
        "--date",
        default=dt.date.today().isoformat(),
        help="Fecha a procesar en formato YYYY-MM-DD (default: hoy)",
    )
    return parser.parse_args()


def parse_reflog_events(start_local, end_local):
    out = run_git(
        [
            "reflog",
            "--date=iso-local",
            f"--since={start_local:%Y-%m-%d %H:%M:%S}",
            f"--until={end_local:%Y-%m-%d %H:%M:%S}",
            "--pretty=%cd|%gs",
        ]
    )

    # git reflog retorna de mas nuevo a mas antiguo; guardamos y luego invertimos
    # para conservar el orden real de eventos en el tiempo.
    events = []
    for line in out.splitlines():
        line = line.strip()
        if not line or "|" not in line:
            continue
        ts_s, msg = line.split("|", 1)
        try:
            ts = dt.datetime.strptime(ts_s.strip(), "%Y-%m-%d %H:%M:%S %z")
        except ValueError:
            continue
        events.append((ts, msg.strip()))

    events.reverse()
    return events


def compute_branch_durations(events, end_local):
    durations = defaultdict(int)
    first_seen = {}
    last_seen = {}

    current_branch = None
    prev_ts = None

    for ts, msg in events:
        if prev_ts is None:
            prev_ts = ts

        if current_branch is not None:
            delta = int((ts - prev_ts).total_seconds())
            if delta > 0:
                durations[current_branch] += delta

        m = CHECKOUT_RE.search(msg)
        if m:
            current_branch = m.group(2).strip()
            if current_branch not in first_seen:
                first_seen[current_branch] = ts
            last_seen[current_branch] = ts
        elif current_branch is not None:
            if current_branch not in first_seen:
                first_seen[current_branch] = ts
            last_seen[current_branch] = ts

        prev_ts = ts

    if current_branch is not None and prev_ts is not None and end_local > prev_ts:
        durations[current_branch] += int((end_local - prev_ts).total_seconds())
        last_seen[current_branch] = end_local

    return durations, first_seen, last_seen


def branch_commits(branch, start_local, end_local):
    try:
        out = run_git(
            [
                "log",
                branch,
                f"--since={start_local:%Y-%m-%d %H:%M:%S}",
                f"--until={end_local:%Y-%m-%d %H:%M:%S}",
                "--pretty=%ad|%h|%s",
                "--date=iso-local",
            ]
        )
    except RuntimeError:
        return []

    commits = []
    for line in out.splitlines():
        if not line.strip() or "|" not in line:
            continue
        parts = line.split("|", 2)
        if len(parts) != 3:
            continue
        ts_s, sha, subject = parts
        try:
            ts = dt.datetime.strptime(ts_s.strip(), "%Y-%m-%d %H:%M:%S %z")
        except ValueError:
            continue
        commits.append((ts, sha.strip(), subject.strip()))

    commits.sort(key=lambda x: x[0])
    return commits


def fmt_hhmm(seconds):
    minutes = int(round(seconds / 60.0))
    h = minutes // 60
    m = minutes % 60
    return f"{h:02d}:{m:02d}"


def fmt_time(ts):
    return ts.strftime("%H:%M") if ts else "-"


def main():
    args = parse_args()

    try:
        day = dt.datetime.strptime(args.date, "%Y-%m-%d").date()
    except ValueError:
        print("Fecha invalida. Use formato YYYY-MM-DD.", file=sys.stderr)
        return 2

    tz = dt.datetime.now().astimezone().tzinfo
    start_local = dt.datetime.combine(day, dt.time(0, 0, 0), tzinfo=tz)
    end_of_day = start_local + dt.timedelta(days=1)
    now = dt.datetime.now(tz=tz)
    end_local = min(now, end_of_day)

    events = parse_reflog_events(start_local, end_local)
    durations, first_seen, last_seen = compute_branch_durations(events, end_local)

    ticket_rows = []
    for branch, seconds in durations.items():
        m = TICKET_BRANCH_RE.match(branch)
        if not m:
            continue
        ticket = m.group(1)
        commits = branch_commits(branch, start_local, end_local)
        commit_count = len(commits)
        first_commit = commits[0][0] if commits else None
        last_commit = commits[-1][0] if commits else None

        ticket_rows.append(
            {
                "ticket": ticket,
                "branch": branch,
                "start": first_seen.get(branch),
                "end": last_seen.get(branch),
                "seconds": seconds,
                "commit_count": commit_count,
                "first_commit": first_commit,
                "last_commit": last_commit,
            }
        )

    if not ticket_rows:
        print(f"No se detecto actividad por ramas de ticket para {args.date}.")
        return 0

    ticket_rows.sort(key=lambda r: (r["start"] or end_local, r["ticket"]))

    print(f"Resumen de bitacora - {args.date}")
    print("")
    print("| Ticket | Rama | Inicio | Fin | Tiempo | Commits |")
    print("|---|---|---:|---:|---:|---:|")
    for row in ticket_rows:
        print(
            "| {ticket} | {branch} | {ini} | {fin} | {dur} | {cc} |".format(
                ticket=row["ticket"],
                branch=row["branch"],
                ini=fmt_time(row["start"]),
                fin=fmt_time(row["end"]),
                dur=fmt_hhmm(row["seconds"]),
                cc=row["commit_count"],
            )
        )

    print("")
    print("Sugerencia para carga manual:")
    for row in ticket_rows:
        print(
            "- Ticket {ticket}: {ini}-{fin} ({dur}) | Rama: {branch}".format(
                ticket=row["ticket"],
                ini=fmt_time(row["start"]),
                fin=fmt_time(row["end"]),
                dur=fmt_hhmm(row["seconds"]),
                branch=row["branch"],
            )
        )

    return 0


if __name__ == "__main__":
    sys.exit(main())