#!/usr/bin/env python3
"""TimeMaster – Development Session Tracker"""

import json
import sys
import os
import argparse
from datetime import datetime, timezone, timedelta

DATA_FILE = os.path.expanduser("~/.claude/timetrack.json")

# ANSI color codes
RESET   = "\033[0m"
BOLD    = "\033[1m"
DIM     = "\033[2m"
RED     = "\033[91m"
GREEN   = "\033[92m"
YELLOW  = "\033[93m"
BLUE    = "\033[94m"
MAGENTA = "\033[95m"
CYAN    = "\033[96m"
WHITE   = "\033[97m"


def colorize(text: str, *codes: str) -> str:
    return "".join(codes) + text + RESET


def load_data() -> dict:
    if not os.path.exists(DATA_FILE):
        return {"sessions": []}
    with open(DATA_FILE, "r", encoding="utf-8") as f:
        return json.load(f)


def save_data(data: dict) -> None:
    with open(DATA_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)


def now_iso() -> str:
    return datetime.now(timezone.utc).isoformat()


def parse_iso(s: str) -> datetime:
    # Python 3.10 fromisoformat handles Z, but 3.8/3.9 don't – be safe
    if s.endswith("Z"):
        s = s[:-1] + "+00:00"
    return datetime.fromisoformat(s)


def format_duration(seconds: float) -> str:
    seconds = int(seconds)
    h = seconds // 3600
    m = (seconds % 3600) // 60
    if h > 0:
        return f"{h}h {m:02d}m"
    return f"{m}m"


def get_running_session(data: dict) -> dict | None:
    for s in data["sessions"]:
        if s["end"] is None:
            return s
    return None


def local_date(dt: datetime) -> str:
    """Return YYYY-MM-DD in local time."""
    return dt.astimezone().strftime("%Y-%m-%d")


def local_display(dt: datetime) -> str:
    return dt.astimezone().strftime("%H:%M")


# ── Commands ──────────────────────────────────────────────────────────────────

def cmd_start(args) -> None:
    description = args.description or ""
    data = load_data()
    running = get_running_session(data)
    if running:
        started_at = parse_iso(running["start"])
        elapsed = (datetime.now(timezone.utc) - started_at).total_seconds()
        print(
            colorize("Fehler: ", RED, BOLD)
            + "Es läuft bereits eine Session.\n"
            + f"  Gestartet: {colorize(local_display(started_at), CYAN)}  "
            + f"Dauer: {colorize(format_duration(elapsed), YELLOW)}"
            + (f"\n  Beschreibung: {running['description']}" if running["description"] else "")
        )
        print(colorize("\nTipp: ", DIM) + colorize("python timetrack.py stop", WHITE) + "  um sie zu beenden.")
        sys.exit(1)

    session = {"start": now_iso(), "end": None, "description": description}
    data["sessions"].append(session)
    save_data(data)
    started_dt = parse_iso(session["start"])
    print(
        colorize("Session gestartet", GREEN, BOLD)
        + f"  {colorize(local_display(started_dt), CYAN)}"
        + (f"\n  {colorize(description, WHITE)}" if description else "")
    )


def cmd_stop(args) -> None:
    data = load_data()
    running = get_running_session(data)
    if not running:
        print(
            colorize("Fehler: ", RED, BOLD)
            + "Keine laufende Session gefunden."
        )
        print(colorize("\nTipp: ", DIM) + colorize("python timetrack.py start", WHITE) + "  um eine zu starten.")
        sys.exit(1)

    end_iso = now_iso()
    running["end"] = end_iso
    save_data(data)

    started_dt = parse_iso(running["start"])
    ended_dt   = parse_iso(end_iso)
    elapsed    = (ended_dt - started_dt).total_seconds()

    print(
        colorize("Session beendet", MAGENTA, BOLD)
        + f"  {colorize(local_display(started_dt), CYAN)} → {colorize(local_display(ended_dt), CYAN)}"
        + f"  Dauer: {colorize(format_duration(elapsed), YELLOW, BOLD)}"
        + (f"\n  {colorize(running['description'], WHITE)}" if running["description"] else "")
    )


def cmd_status(args) -> None:
    data = load_data()
    running = get_running_session(data)
    if not running:
        print(colorize("Keine laufende Session.", DIM))
        return

    started_dt = parse_iso(running["start"])
    elapsed    = (datetime.now(timezone.utc) - started_dt).total_seconds()

    print(colorize("Laufende Session", GREEN, BOLD))
    print(f"  Gestartet : {colorize(started_dt.astimezone().strftime('%Y-%m-%d %H:%M'), CYAN)}")
    print(f"  Dauer     : {colorize(format_duration(elapsed), YELLOW, BOLD)}")
    if running["description"]:
        print(f"  Beschr.   : {colorize(running['description'], WHITE)}")


def cmd_report(args) -> None:
    data = load_data()
    sessions = data["sessions"]

    # Determine filter
    now_local = datetime.now(timezone.utc).astimezone()
    filter_label = ""

    if args.week:
        # Monday of current week
        week_start = (now_local - timedelta(days=now_local.weekday())).replace(
            hour=0, minute=0, second=0, microsecond=0
        )
        week_end = week_start + timedelta(days=7)
        def in_range(start_dt):
            loc = start_dt.astimezone()
            return week_start <= loc < week_end
        filter_label = f"KW {now_local.isocalendar()[1]}  ({week_start.strftime('%d.%m.')} – {(week_end - timedelta(days=1)).strftime('%d.%m.%Y')})"

    elif args.month:
        def in_range(start_dt):
            loc = start_dt.astimezone()
            return loc.year == now_local.year and loc.month == now_local.month
        filter_label = now_local.strftime("%B %Y")

    else:
        def in_range(_):
            return True
        filter_label = "Gesamt"

    # Build filtered & sorted list
    filtered = []
    for s in sessions:
        start_dt = parse_iso(s["start"])
        if not in_range(start_dt):
            continue
        if s["end"] is not None:
            end_dt  = parse_iso(s["end"])
            elapsed = (end_dt - start_dt).total_seconds()
            ongoing = False
        else:
            end_dt  = datetime.now(timezone.utc)
            elapsed = (end_dt - start_dt).total_seconds()
            ongoing = True
        filtered.append({
            "date":        local_date(start_dt),
            "start_dt":    start_dt,
            "end_dt":      end_dt,
            "elapsed":     elapsed,
            "description": s["description"],
            "ongoing":     ongoing,
        })

    filtered.sort(key=lambda x: x["start_dt"])

    if not filtered:
        print(colorize(f"Keine Sessions für: {filter_label}", DIM))
        return

    # Column widths
    COL_DATE  = 12
    COL_TIME  = 13   # HH:MM – HH:MM
    COL_DUR   = 9
    COL_DESC  = 40

    sep_char = "─"
    total_width = COL_DATE + COL_TIME + COL_DUR + COL_DESC + 3  # 3 separators

    def hr(char=sep_char):
        return colorize(char * total_width, DIM)

    def row(date, time_range, duration, description, color=WHITE):
        d    = date.ljust(COL_DATE)
        t    = time_range.ljust(COL_TIME)
        dur  = duration.ljust(COL_DUR)
        desc = description[:COL_DESC].ljust(COL_DESC)
        return colorize(f"{d} {t} {dur} {desc}", color)

    # Header
    print()
    print(colorize(f"  TimeMaster – Report: {filter_label}", BOLD, BLUE))
    print(hr())
    print(row(
        colorize("Datum",       BOLD, WHITE),
        colorize("Zeit",        BOLD, WHITE),
        colorize("Dauer",       BOLD, WHITE),
        colorize("Beschreibung",BOLD, WHITE),
    ))
    print(hr())

    # Group by date
    day_groups: dict[str, list] = {}
    for entry in filtered:
        day_groups.setdefault(entry["date"], []).append(entry)

    grand_total = 0.0

    for date_str, entries in day_groups.items():
        day_total = 0.0
        for e in entries:
            time_range = f"{local_display(e['start_dt'])}–{local_display(e['end_dt'])}"
            dur_str    = format_duration(e["elapsed"])
            if e["ongoing"]:
                dur_str += colorize(" ●", GREEN)
                time_range += colorize(" ●", GREEN)
            print(row(
                date_str,
                time_range,
                dur_str,
                e["description"] or colorize("–", DIM),
            ))
            day_total  += e["elapsed"]
            grand_total += e["elapsed"]
            date_str = ""  # only show date on first row per day

        # Day subtotal
        day_label = colorize(f"  Tagessumme", DIM)
        day_dur   = colorize(format_duration(day_total), YELLOW, BOLD)
        print(f"{' ' * COL_DATE} {'':>{COL_TIME}} {day_dur}")
        print(hr())

    # Grand total
    print(
        f"{'Gesamt'.ljust(COL_DATE + COL_TIME + 2)}"
        + colorize(format_duration(grand_total), CYAN, BOLD)
    )
    print()


# ── Entry point ───────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(
        prog="timetrack",
        description="TimeMaster – Development Session Tracker",
    )
    sub = parser.add_subparsers(dest="command", metavar="command")

    p_start = sub.add_parser("start", help="Session starten")
    p_start.add_argument("description", nargs="?", default="", help="Optionale Beschreibung")

    sub.add_parser("stop",   help="Laufende Session beenden")
    sub.add_parser("status", help="Status der laufenden Session")

    p_report = sub.add_parser("report", help="Sessionen als Tabelle anzeigen")
    grp = p_report.add_mutually_exclusive_group()
    grp.add_argument("--week",  action="store_true", help="Nur aktuelle Woche")
    grp.add_argument("--month", action="store_true", help="Nur aktueller Monat")

    args = parser.parse_args()

    dispatch = {
        "start":  cmd_start,
        "stop":   cmd_stop,
        "status": cmd_status,
        "report": cmd_report,
    }

    if args.command not in dispatch:
        parser.print_help()
        sys.exit(1)

    dispatch[args.command](args)


if __name__ == "__main__":
    main()
