#!/usr/bin/env python3
"""AI-Radar Sprint B — Orchestrator.

Fetcht alle registrierten Plattformen, normalisiert, dedupliziert gegen
seen_urls.txt und schreibt Tages-Snapshot. Synthese bleibt manuell (Sprint C).
"""
from __future__ import annotations

import argparse
import datetime as dt
import json
import logging
import sys
from pathlib import Path

from platforms import PLATFORMS
from normalizer import normalize_items
from dedupe import filter_unseen, mark_seen
from snapshot import write_snapshot

STATE_DIR = Path("/var/lib/aria-radar/state")
SNAPSHOT_DIR = Path("/var/lib/aria-radar/snapshots")
SNAPSHOT_RETENTION_DAYS = 30

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
)
log = logging.getLogger("aria-radar")


def cleanup_old_snapshots(retention_days: int = SNAPSHOT_RETENTION_DAYS) -> int:
    cutoff = dt.date.today() - dt.timedelta(days=retention_days)
    removed = 0
    for snap in SNAPSHOT_DIR.glob("*.json"):
        try:
            snap_date = dt.date.fromisoformat(snap.stem)
        except ValueError:
            continue
        if snap_date < cutoff:
            snap.unlink()
            removed += 1
    return removed


def run(dry_run: bool = False, since_hours: int = 24) -> int:
    since = dt.datetime.now(dt.timezone.utc) - dt.timedelta(hours=since_hours)
    all_items: list[dict] = []
    source_counts: dict[str, int] = {}
    errors: dict[str, str] = {}

    for name, fetch in PLATFORMS.items():
        log.info("fetching %s (since=%s)", name, since.isoformat())
        try:
            items = fetch(since=since)
        except Exception as exc:  # noqa: BLE001 — defensive at boundary
            log.exception("platform %s failed: %s", name, exc)
            errors[name] = str(exc)
            items = []
        source_counts[name] = len(items)
        all_items.extend(items)

    log.info("fetched %d items across %d platforms", len(all_items), len(PLATFORMS))

    normalized = normalize_items(all_items)
    seen_file = STATE_DIR / "seen_urls.txt"
    new_items = filter_unseen(normalized, seen_file)
    log.info("after dedupe: %d new items (was %d)", len(new_items), len(normalized))

    if dry_run:
        log.info("dry-run — no snapshot, no seen-state update")
        return 0

    today = dt.date.today().isoformat()
    snapshot_path = SNAPSHOT_DIR / f"{today}.json"
    write_snapshot(
        path=snapshot_path,
        date=today,
        source_counts=source_counts,
        items=new_items,
        errors=errors,
    )
    mark_seen(new_items, seen_file)

    removed = cleanup_old_snapshots()
    if removed:
        log.info("cleaned up %d snapshots older than %dd", removed, SNAPSHOT_RETENTION_DAYS)

    log.info("snapshot written: %s (%d items, %d errors)", snapshot_path, len(new_items), len(errors))
    return 0


def main() -> int:
    parser = argparse.ArgumentParser(description="AI-Radar Sprint B Fetcher")
    parser.add_argument("--dry-run", action="store_true", help="fetch but skip snapshot/state writes")
    parser.add_argument("--since-hours", type=int, default=24, help="lookback window in hours")
    args = parser.parse_args()
    return run(dry_run=args.dry_run, since_hours=args.since_hours)


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