#!/usr/bin/env python3
"""PC-only Dropbox landing paths for the 4-Board Test Fixture.

Pis (identical on all four boards):
  ~/EtherGold/4-Board Test Fixture/fixture-timing/data/
  ~/EtherGold/4-Board Test Fixture/fixture-timing/logs/

PC Dropbox landing (one folder per Pi upload destination):
  .../4-Board Test Fixture/1/data/events.jsonl
  .../4-Board Test Fixture/2/data/events.jsonl
  ...

Legacy uploads used .../N/topboxN/data/ — resolve_* helpers prefer canonical N/data/
when present, else newest session_start among candidates (for old archives).
"""

from __future__ import annotations

import json
from datetime import datetime
from pathlib import Path
from typing import Optional

CAPTURE_FILES = (
    "events.jsonl",
    "packets.raw",
    "fixture_stats.json",
    "raw_stats.json",
)

LOG_FILES = (
    "fixture_listen.log",
    "fixture_bridge.log",
    "raw_capture.log",
    "uartd.log",
    "bridge_build_check.log",
    "listen_build_check.log",
)


def landing_root(fixture_root: Path, pos: int) -> Path:
    return fixture_root / str(pos)


def landing_data_dir(fixture_root: Path, pos: int) -> Path:
    return landing_root(fixture_root, pos) / "data"


def landing_logs_dir(fixture_root: Path, pos: int) -> Path:
    return landing_root(fixture_root, pos) / "logs"


def events_jsonl_candidates(root: Path, pos: int) -> list[Path]:
    base = root / str(pos)
    out: list[Path] = []
    for rel in (Path("data") / "events.jsonl", Path(f"topbox{pos}") / "data" / "events.jsonl"):
        p = base / rel
        if p.is_file():
            out.append(p)
    return out


def read_session_start_utc(path: Path) -> Optional[str]:
    try:
        with path.open(encoding="utf-8") as fh:
            line = fh.readline().strip()
        if not line:
            return None
        row = json.loads(line)
        if row.get("ev") != "session_start":
            return None
        utc = row.get("utc")
        return str(utc) if utc else None
    except (OSError, json.JSONDecodeError, ValueError):
        return None


def _utc_sort_key(utc: Optional[str]) -> datetime:
    if not utc:
        return datetime.min
    try:
        return datetime.fromisoformat(utc.replace("Z", "+00:00"))
    except ValueError:
        return datetime.min


def resolve_events_jsonl(root: Path, pos: int) -> Optional[Path]:
    """Newest session_start among known landing paths; tie-break prefers N/data/."""
    candidates = events_jsonl_candidates(root, pos)
    if not candidates:
        return None
    canonical = landing_data_dir(root, pos) / "events.jsonl"
    if canonical in candidates and len(candidates) == 1:
        return canonical

    def score(p: Path) -> tuple:
        utc = read_session_start_utc(p)
        prefer_canonical = 1 if p == canonical else 0
        return (_utc_sort_key(utc), prefer_canonical)

    return max(candidates, key=score)


def resolve_data_dir(root: Path, pos: int) -> Optional[Path]:
    ev = resolve_events_jsonl(root, pos)
    return ev.parent if ev else None


def resolve_logs_dir(root: Path, pos: int) -> Optional[Path]:
    data = resolve_data_dir(root, pos)
    if data is None:
        return None
    # data is .../something/data → logs is sibling under same parent
    logs = data.parent / "logs"
    return logs if logs.is_dir() else None


def resolve_capture_file(root: Path, pos: int, name: str) -> Optional[Path]:
    data = resolve_data_dir(root, pos)
    if data is None:
        return None
    p = data / name
    return p if p.is_file() else None
