#!/usr/bin/env python3
"""Production log rotation + age-based cleanup (errors.jsonl, supervisor logs)."""

from __future__ import annotations

import os
import time
from pathlib import Path

# 10 KiB rollover; delete rotated files older than 24 h (override via env).
DEFAULT_MAX_BYTES = 10240
DEFAULT_MAX_AGE_S = 86400


def utc_stamp() -> str:
    return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())


def env_max_bytes(name: str, default: int = DEFAULT_MAX_BYTES) -> int:
    raw = os.environ.get(name, "").strip()
    if not raw:
        return default
    try:
        return int(raw)
    except ValueError:
        return default


def env_max_age_s(name: str = "FIXTURE_PROD_LOG_MAX_AGE_S", default: float = DEFAULT_MAX_AGE_S) -> float:
    raw = os.environ.get(name, "").strip()
    if not raw:
        return default
    try:
        return float(raw)
    except ValueError:
        return default


def rotate_if_large(path: Path, max_bytes: int) -> bool:
    """Rotate active log to path.{UTCstamp} when size >= max_bytes."""
    if max_bytes <= 0 or not path.is_file():
        return False
    try:
        if path.stat().st_size < max_bytes:
            return False
    except OSError:
        return False
    dest = path.with_name(f"{path.name}.{utc_stamp()}")
    # Extremely unlikely: same-second collision — bump suffix.
    n = 1
    while dest.exists():
        dest = path.with_name(f"{path.name}.{utc_stamp()}.{n}")
        n += 1
    path.rename(dest)
    return True


def prune_rotated_logs(directory: Path, base_name: str, max_age_s: float) -> int:
    """Delete directory/base_name.* older than max_age_s. Keeps active base_name."""
    if max_age_s <= 0 or not directory.is_dir():
        return 0
    cutoff = time.time() - max_age_s
    prefix = f"{base_name}."
    removed = 0
    for entry in directory.iterdir():
        if not entry.is_file():
            continue
        if entry.name == base_name:
            continue
        if not entry.name.startswith(prefix):
            continue
        try:
            if entry.stat().st_mtime < cutoff:
                entry.unlink()
                removed += 1
        except OSError:
            pass
    return removed


def manage_prod_log(
    path: Path,
    *,
    max_bytes: int | None = None,
    max_age_s: float | None = None,
) -> int:
    """Rotate if large, then prune stale rotated siblings. Returns files removed."""
    if max_bytes is None:
        max_bytes = env_max_bytes("FIXTURE_PROD_ERRORS_MAX_BYTES")
    if max_age_s is None:
        max_age_s = env_max_age_s()
    rotate_if_large(path, max_bytes)
    return prune_rotated_logs(path.parent, path.name, max_age_s)
