"""bincio segments — segment management CLI commands."""

from __future__ import annotations

import json
import sys
from datetime import datetime, timezone
from pathlib import Path

import click


def _dt(s: str) -> datetime:
    return datetime.fromisoformat(s.replace("Z", "+00:00"))


@click.group("segments")
def segments_group() -> None:
    """Manage segments and detect efforts."""


@segments_group.command("detect")
@click.option("--data-dir", required=True, type=click.Path(), help="BAS data directory (e.g. /var/bincio)")
@click.option("--handle", required=True, help="User handle to run detection for")
@click.option("--activity-id", default=None, help="Limit to a single activity ID (optional)")
@click.option("--segment-id", default=None, help="Limit to a single segment ID (optional)")
@click.option("--fresh", is_flag=True, default=False, help="Clear existing efforts before detecting")
def detect_cmd(data_dir: str, handle: str, activity_id: str | None, segment_id: str | None, fresh: bool) -> None:
    """Retroactively detect segment efforts for stored activities.

    Walks every activity with GPS data, runs the detection algorithm against
    all (or a single) segment, and persists any new efforts found.
    """
    from bincio.segments.detect import track_from_timeseries_json, detect_one, detect_all
    from bincio.segments import store as _store

    dd = Path(data_dir).expanduser().resolve()
    user_dir = dd / handle
    acts_dir = user_dir / "activities"

    if not acts_dir.exists():
        click.echo(f"No activities directory at {acts_dir}", err=True)
        sys.exit(1)

    # Choose which segments to check.
    if segment_id:
        seg = _store.load_segment(dd, segment_id)
        if seg is None:
            click.echo(f"Segment not found: {segment_id}", err=True)
            sys.exit(1)
        segments = [seg]
    else:
        segments = _store.list_segments(dd)

    if not segments:
        click.echo("No segments defined.", err=True)
        sys.exit(0)

    if fresh:
        for seg in segments:
            _store.save_efforts(dd, handle, seg.id, [])
        click.echo(f"Cleared existing efforts for {len(segments)} segment(s).")

    # Choose which activities to process.
    if activity_id:
        detail_files = [acts_dir / f"{activity_id}.json"]
    else:
        detail_files = sorted(acts_dir.glob("*.json"))
        # Exclude timeseries files.
        detail_files = [f for f in detail_files if ".timeseries." not in f.name]

    total_efforts = 0
    processed = 0

    for detail_path in detail_files:
        try:
            detail = json.loads(detail_path.read_text(encoding="utf-8"))
        except Exception:
            continue

        ts_url = detail.get("timeseries_url")
        if not ts_url:
            continue

        act_id   = detail.get("id", detail_path.stem)
        sport    = detail.get("sport", "other")
        started  = detail.get("started_at")
        if not started:
            continue
        try:
            started_at = _dt(started)
        except Exception:
            continue

        ts_path = user_dir / ts_url
        if not ts_path.exists():
            continue
        try:
            ts = json.loads(ts_path.read_text(encoding="utf-8"))
        except Exception:
            continue

        track = track_from_timeseries_json(ts, act_id, sport, started_at)
        if track is None:
            continue

        processed += 1
        for seg in segments:
            from bincio.segments.detect import detect_one
            efforts = detect_one(track, seg)
            for effort in efforts:
                _store.add_effort(dd, handle, seg.id, effort)
            if efforts:
                click.echo(
                    f"  {act_id}: {len(efforts)} effort(s) on '{seg.name}' "
                    f"({', '.join(str(e.elapsed_s) + 's' for e in efforts)})"
                )
                total_efforts += len(efforts)

    click.echo(f"\nProcessed {processed} activities, found {total_efforts} effort(s).")
