#!/usr/bin/env python3
# Issue #115: Kintsugi self-healing gap reconciliation
"""Kintsugi CLI: Self-healing gap reconciliation for ClickHouse cache.

Usage:
    python scripts/kintsugi.py                       # Single pass
    python scripts/kintsugi.py --daemon              # Long-running (fast defaults)
    python scripts/kintsugi.py --dry-run             # Discover + classify only
    python scripts/kintsugi.py --symbol BTCUSDT      # Filter by symbol
    python scripts/kintsugi.py --max-repairs 2        # Limit repairs per pass

Exit codes:
    0 - All shards healed (or no shards found)
    1 - Some repairs failed
    2 - Error (connection, configuration)
"""

from __future__ import annotations

import argparse
import sys


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Kintsugi: self-healing gap reconciliation",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument(
        "--daemon",
        action="store_true",
        help="Run as long-lived daemon with adaptive polling. "
        "Always uses reverse chronological processing, parallel daily "
        "segments (8 workers), and skips microstructure (OHLCV only).",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Discover and classify shards without repairing",
    )
    parser.add_argument(
        "--threshold",
        type=int,
        default=None,
        help="Filter to a specific threshold in dbps (e.g., 250)",
    )
    parser.add_argument(
        "--max-repairs",
        type=int,
        default=None,
        help="Max repairs per pass (default: 10)",
    )
    parser.add_argument(
        "--interval-clean",
        type=int,
        default=300,
        help="Daemon sleep when clean, seconds (default: 300)",
    )
    parser.add_argument(
        "--interval-active",
        type=int,
        default=60,
        help="Daemon sleep when active, seconds (default: 60)",
    )
    parser.add_argument(
        "--replay-dead-letters",
        action="store_true",
        help="Replay dead-letter files from sidecar flush failures",
    )
    parser.add_argument(
        "--include-microstructure",
        action="store_true",
        help="Include microstructure features (26 extra columns). "
        "Off by default — OHLCV + trade IDs only. Much faster.",
    )
    parser.add_argument(
        "--verbose",
        "-v",
        action="store_true",
        help="Enable verbose logging",
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()

    import setproctitle

    mode = "daemon" if args.daemon else "single-pass"
    thr_filter = f" threshold={args.threshold}" if args.threshold else " all-thresholds"
    setproctitle.setproctitle(
        f"odb-kintsugi: {mode}{thr_filter} "
        f"max-repairs={args.max_repairs or 'env'} "
        f"interval-active={args.interval_active}s interval-clean={args.interval_clean}s"
    )

    from opendeviationbar.logging import setup_service_logging

    setup_service_logging("kintsugi", verbose=args.verbose)

    from opendeviationbar.kintsugi import (
        kintsugi_daemon,
        kintsugi_pass,
        replay_dead_letters,
    )

    # Replay dead-letters first (if requested or in daemon mode)
    if args.replay_dead_letters or args.daemon:
        replayed = replay_dead_letters()
        if replayed > 0:
            from loguru import logger

            logger.info("replayed {} dead-letter bars", replayed)

    max_repairs = args.max_repairs  # None → kintsugi_daemon() reads from KintsugiConfig (env var)

    if args.daemon:
        kintsugi_daemon(
            interval_clean_s=args.interval_clean,
            interval_active_s=args.interval_active,
            threshold=args.threshold,
            include_microstructure=args.include_microstructure,
            max_repairs=max_repairs,
        )
        return 0

    # Single pass
    results = kintsugi_pass(
        dry_run=args.dry_run,
        threshold=args.threshold,
        verbose=args.verbose,
        include_microstructure=args.include_microstructure,
        max_repairs=max_repairs,
    )

    if args.dry_run:
        return 0

    failed = sum(1 for r in results if not r.healed)
    return 1 if failed > 0 else 0


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