"""Batch (non-interactive) disk health checks, self-tests, and btrfs scrubs."""

import sys
import subprocess

import click

from jusfltuls.disk_scanner import scan_disks, get_btrfs_last_scrub_hours
from jusfltuls.smartctl import SmartHealthMonitor
from jusfltuls.shell_calls import (
    build_sudo_btrfs_scrub_start,
    set_debug_mode,
    get_debug_mode,
)

# Thresholds
LONG_TEST_MAX_HOURS  = 168   # launch extended test if last one is older than this
SHORT_TEST_MAX_HOURS = 48    # launch short test if no recent short AND no recent long
SCRUB_WARN_HOURS     = 600   # flag scrub as stale


# ── ANSI helpers ──────────────────────────────────────────────────────────────

def _red(text: str) -> str:
    return f"\033[31m{text}\033[0m"

def _green(text: str) -> str:
    return f"\033[32m{text}\033[0m"

def _yellow(text: str) -> str:
    return f"\033[33m{text}\033[0m"

def _bold(text: str) -> str:
    return f"\033[1m{text}\033[0m"


# ── Core checks ───────────────────────────────────────────────────────────────

def check_disks(verbose: bool = True) -> bool:
    """Scan all disks and report SMART health + btrfs errors.

    Returns True if everything is healthy, False otherwise.
    """
    disks, error = scan_disks()
    if error:
        click.echo(_red(f"ERROR: {error}"), err=True)
        return False

    all_ok = True
    monitor = SmartHealthMonitor()

    for disk in disks:
        health = monitor.get_disk_health(disk.device_path)
        disk.health_status            = health.overall_health
        disk.power_on_hours           = health.power_on_hours
        disk.last_short_test_hours_ago = health.last_short_test_hours_ago
        disk.last_long_test_hours_ago  = health.last_long_test_hours_ago
        disk.short_test_in_progress    = health.short_test_in_progress
        disk.long_test_in_progress     = health.long_test_in_progress

        # ── SMART health ──
        if health.overall_health == "PASSED":
            status_str = _green("PASSED")
        elif health.overall_health == "FAILED":
            status_str = _red("FAILED")
            all_ok = False
        else:
            status_str = _yellow(health.overall_health or "UNKNOWN")

        poh = f"{health.power_on_hours}h" if health.power_on_hours else "?"
        click.echo(f"{_bold(disk.name):20}  health={status_str}  POH={poh}")

        # ── btrfs partition errors ──
        for part in disk.partitions:
            if part.filesystem != "btrfs":
                continue
            err = part.btrfs_errors or "?"
            if err == "ERR":
                click.echo(f"  {part.name:14}  btrfs_errors={_red('ERR')}")
                all_ok = False
            elif verbose:
                click.echo(f"  {part.name:14}  btrfs_errors={_green('OK')}")

    return all_ok


def run_tests(dry_run: bool = False) -> None:
    """Launch SMART self-tests where needed.

    Rules:
      - If last extended (long) test is older than LONG_TEST_MAX_HOURS  → launch extended
      - Else if last short test is older than SHORT_TEST_MAX_HOURS       → launch short
      - If a test of any kind is already in progress                     → skip that disk
    """
    disks, error = scan_disks()
    if error:
        click.echo(_red(f"ERROR: {error}"), err=True)
        return

    monitor = SmartHealthMonitor()

    for disk in disks:
        health = monitor.get_disk_health(disk.device_path)

        if health.short_test_in_progress or health.long_test_in_progress:
            kind = "short" if health.short_test_in_progress else "long"
            pct  = (health.short_test_remaining_percent
                    if health.short_test_in_progress
                    else health.long_test_remaining_percent)
            click.echo(f"{disk.name}: {kind} test already in progress ({pct}% done) — skipping")
            continue

        long_h  = health.last_long_test_hours_ago
        short_h = health.last_short_test_hours_ago

        if long_h is None or long_h > LONG_TEST_MAX_HOURS:
            action = "extended"
            age_str = f"{long_h}h" if long_h is not None else "never"
            click.echo(f"{disk.name}: last extended test {age_str} ago → "
                       + (_yellow("would launch extended") if dry_run else "launching extended test"))
            if not dry_run:
                ok, msg = monitor.start_long_test(disk.device_path)
                click.echo(f"  {'OK' if ok else 'FAIL'}: {msg}")
        elif short_h is None or short_h > SHORT_TEST_MAX_HOURS:
            action = "short"
            age_str = f"{short_h}h" if short_h is not None else "never"
            click.echo(f"{disk.name}: last short test {age_str} ago → "
                       + (_yellow("would launch short") if dry_run else "launching short test"))
            if not dry_run:
                ok, msg = monitor.start_short_test(disk.device_path)
                click.echo(f"  {'OK' if ok else 'FAIL'}: {msg}")
        else:
            click.echo(f"{disk.name}: tests up to date  "
                       f"(short={short_h}h, long={long_h}h) — nothing to do")


def run_scrubs(dry_run: bool = False) -> None:
    """Launch btrfs scrubs where the last completed scrub is older than SCRUB_WARN_HOURS."""
    disks, error = scan_disks()
    if error:
        click.echo(_red(f"ERROR: {error}"), err=True)
        return

    for disk in disks:
        for part in disk.partitions:
            if part.filesystem != "btrfs" or not part.mountpoint:
                continue

            # Skip partitions with a scrub already running
            if part.btrfs_scrub_status:
                click.echo(f"{part.name} ({part.mountpoint}): scrub in progress ({part.btrfs_scrub_status}) — skipping")
                continue

            last_h = get_btrfs_last_scrub_hours(part.mountpoint)
            age_str = f"{last_h}h" if last_h is not None else "never"

            if last_h is None or last_h > SCRUB_WARN_HOURS:
                click.echo(
                    f"{part.name} ({part.mountpoint}): last scrub {age_str} → "
                    + (_yellow("would start scrub") if dry_run else "starting scrub")
                )
                if not dry_run:
                    cmd = build_sudo_btrfs_scrub_start(part.mountpoint)
                    if get_debug_mode():
                        click.echo(f"  [DEBUG] {' '.join(cmd)}")
                    try:
                        subprocess.Popen(
                            cmd,
                            stdout=subprocess.DEVNULL,
                            stderr=subprocess.DEVNULL,
                            start_new_session=True,
                        )
                        click.echo(f"  OK: scrub started on {part.name}")
                    except Exception as exc:
                        click.echo(_red(f"  FAIL: {exc}"))
            else:
                click.echo(f"{part.name} ({part.mountpoint}): last scrub {age_str} — ok")


# ── CLI ───────────────────────────────────────────────────────────────────────

@click.command()
@click.option("--check",  "mode", flag_value="check",  default=True,
              help="Check SMART health and btrfs errors (default).")
@click.option("--test",   "mode", flag_value="test",
              help="Launch SMART self-tests where needed.")
@click.option("--scrub",  "mode", flag_value="scrub",
              help="Launch btrfs scrubs where needed.")
@click.option("--all",    "mode", flag_value="all",
              help="Run check, then test, then scrub.")
@click.option("--dry-run", is_flag=True, default=False,
              help="Show what would be done without actually doing it.")
@click.option("--debug", "-d", is_flag=True, default=False,
              help="Enable debug mode.")
def main(mode: str, dry_run: bool, debug: bool) -> None:
    """Non-interactive disk health check, self-test, and scrub management.

    Default action (--check): report SMART health and btrfs errors.
    Use --test to automatically trigger self-tests where overdue.
    Use --scrub to automatically trigger btrfs scrubs where overdue.
    Use --all to do all three in sequence.

    Thresholds:
      Extended test: last run > 168 h ago  (one week)
      Short test:    last run >  48 h ago  (two days)
      Btrfs scrub:   last run > 600 h ago  (~25 days)
    """
    set_debug_mode(debug)

    if mode in ("check", "all"):
        click.echo(_bold("=== SMART health + btrfs error check ==="))
        ok = check_disks()
        if ok:
            click.echo(_green("All disks healthy."))
        else:
            click.echo(_red("Issues found — see above."))
        click.echo()

    if mode in ("test", "all"):
        click.echo(_bold("=== SMART self-test management ==="))
        run_tests(dry_run=dry_run)
        click.echo()

    if mode in ("scrub", "all"):
        click.echo(_bold("=== Btrfs scrub management ==="))
        run_scrubs(dry_run=dry_run)
        click.echo()


if __name__ == "__main__":
    main()
