"""CLI commands for maintenance window management."""

from __future__ import annotations

from datetime import datetime, timedelta

import click

from oclawma.cli_ui import (
    accent,
    bullet,
    header,
    highlight,
    key_value,
    print_error,
    print_info,
    print_success,
    print_warning,
    subheader,
)
from oclawma.maintenance import (
    MaintenanceManager,
    RecurrenceType,
    get_maintenance_manager,
)


def get_manager(ctx: click.Context) -> MaintenanceManager:
    """Get maintenance manager from context or create default."""
    if hasattr(ctx, "obj") and ctx.obj and "maintenance_manager" in ctx.obj:
        return ctx.obj["maintenance_manager"]
    return get_maintenance_manager()


@click.group(name="maintenance")
@click.pass_context
def maintenance_cli(ctx: click.Context) -> None:
    """Manage scheduled maintenance windows."""
    pass


@maintenance_cli.command(name="status")
@click.pass_context
def maintenance_status(ctx: click.Context) -> None:
    """Show current maintenance status."""
    manager = get_manager(ctx)
    state = manager.get_maintenance_state()
    stats = manager.get_stats()

    header("Maintenance Status")

    if state.in_maintenance:
        print_warning("🔧 MAINTENANCE MODE ACTIVE")
        if state.active_window:
            key_value("Window", state.active_window.name)
            key_value("Description", state.active_window.description or "N/A")
            key_value(
                "Started", state.maintenance_start.isoformat() if state.maintenance_start else "N/A"
            )
            key_value("Ends", state.maintenance_end.isoformat() if state.maintenance_end else "N/A")
            if state.message:
                key_value("Message", state.message)
    else:
        print_success("✅ System operational")

    print()
    subheader("Statistics")
    key_value("Total Windows", str(stats["total_windows"]))
    key_value("Enabled Windows", str(stats["enabled_windows"]))
    key_value("Active Windows", str(stats["active_windows"]))
    key_value("Upcoming Windows", str(stats["upcoming_windows"]))

    if state.next_window:
        print()
        subheader("Next Scheduled Maintenance")
        key_value("Name", state.next_window.name)
        key_value("Starts", state.next_window.start_time.isoformat())
        duration_mins = int(state.next_window.duration_seconds() / 60)
        key_value("Duration", f"{duration_mins} minutes")


@maintenance_cli.command(name="list")
@click.option(
    "--active",
    "-a",
    is_flag=True,
    help="Show only currently active windows",
)
@click.option(
    "--enabled",
    "-e",
    is_flag=True,
    help="Show only enabled windows",
)
@click.option(
    "--limit",
    "-l",
    type=int,
    default=20,
    help="Maximum number of results",
)
@click.pass_context
def maintenance_list(
    ctx: click.Context,
    active: bool,
    enabled: bool,
    limit: int,
) -> None:
    """List scheduled maintenance windows."""
    manager = get_manager(ctx)
    windows = manager.list_windows(
        active_only=active,
        enabled_only=enabled,
        limit=limit,
    )

    if not windows:
        print_info("No maintenance windows found.")
        return

    header("Maintenance Windows")

    for window in windows:
        status_icon = "🔧" if window.is_active() else "⏰" if window.enabled else "🚫"
        click.echo(f"\n{status_icon} {highlight(window.name)} (ID: {window.id})")

        if window.description:
            bullet(f"Description: {window.description}")

        bullet(f"Start: {accent(window.start_time.isoformat())}")
        bullet(f"End: {accent(window.end_time.isoformat())}")
        bullet(f"Timezone: {window.timezone}")
        bullet(f"Recurring: {window.recurring.value}")

        if window.recurring != RecurrenceType.NONE and window.recurrence_end:
            bullet(f"Recurrence ends: {window.recurrence_end.isoformat()}")

        status_str = window.status.value
        if window.is_active():
            status_str = f"{status_str} (ACTIVE)"
        elif not window.enabled:
            status_str = f"{status_str} (DISABLED)"

        bullet(f"Status: {status_str}")

        duration_mins = int(window.duration_seconds() / 60)
        bullet(f"Duration: {duration_mins} minutes")


@maintenance_cli.command(name="schedule")
@click.option(
    "--name",
    "-n",
    required=True,
    help="Name for the maintenance window",
)
@click.option(
    "--start",
    "-s",
    "start_time_str",
    required=True,
    help="Start time (ISO format or 'now', 'tomorrow', 'in 1 hour')",
)
@click.option(
    "--duration",
    "-d",
    type=int,
    default=60,
    help="Duration in minutes",
)
@click.option(
    "--description",
    "-D",
    help="Description of the maintenance",
)
@click.option(
    "--timezone",
    "-t",
    default="UTC",
    help="Timezone (e.g., UTC, America/New_York)",
)
@click.option(
    "--recurring",
    "-r",
    type=click.Choice(["none", "daily", "weekly", "monthly"]),
    default="none",
    help="Recurrence pattern",
)
@click.option(
    "--recurrence-end",
    "-R",
    help="When recurrence should end (ISO format)",
)
@click.pass_context
def maintenance_schedule(
    ctx: click.Context,
    name: str,
    start_time_str: str,
    duration: int,
    description: str | None,
    timezone: str,
    recurring: str,
    recurrence_end: str | None,
) -> None:
    """Schedule a new maintenance window."""
    manager = get_manager(ctx)

    # Parse start time
    start_time = _parse_time(start_time_str)
    if start_time is None:
        print_error(f"Invalid start time: {start_time_str}")  # type: ignore
        raise click.Exit(1)  # type: ignore

    # Parse recurrence end
    recurrence_end_dt = None
    if recurrence_end:
        try:
            recurrence_end_dt = datetime.fromisoformat(recurrence_end)
        except ValueError:
            print_error(f"Invalid recurrence end time: {recurrence_end}")  # type: ignore
            raise click.Exit(1) from None  # type: ignore

    # Map recurrence string to enum
    recurrence_map = {
        "none": RecurrenceType.NONE,
        "daily": RecurrenceType.DAILY,
        "weekly": RecurrenceType.WEEKLY,
        "monthly": RecurrenceType.MONTHLY,
    }

    try:
        window = manager.schedule_window(
            name=name,
            start=start_time,
            duration_minutes=duration,
            description=description,
            timezone=timezone,
            recurring=recurrence_map[recurring],
            recurrence_end=recurrence_end_dt,
        )

        print_success(f"Scheduled maintenance window: {window.name}")
        key_value("ID", str(window.id))
        key_value("Start", window.start_time.isoformat())
        key_value("End", window.end_time.isoformat())
        key_value("Duration", f"{duration} minutes")
        key_value("Recurring", recurring)

    except Exception as e:
        print_error(f"Failed to schedule maintenance: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="update")
@click.argument("window_id", type=int)
@click.option("--name", "-n", help="New name")
@click.option("--start", "start_time_str", help="New start time (ISO format)")
@click.option("--end", "end_time_str", help="New end time (ISO format)")
@click.option("--description", "-D", help="New description")
@click.option(
    "--enable/--disable",
    default=None,
    help="Enable or disable the window",
)
@click.pass_context
def maintenance_update(
    ctx: click.Context,
    window_id: int,
    name: str | None,
    start_time_str: str | None,
    end_time_str: str | None,
    description: str | None,
    enable: bool | None,
) -> None:
    """Update an existing maintenance window."""
    manager = get_manager(ctx)

    # Parse times
    start_time = None
    if start_time_str:
        try:
            start_time = datetime.fromisoformat(start_time_str)
        except ValueError:
            print_error(f"Invalid start time: {start_time_str}")  # type: ignore
            raise click.Exit(1) from None  # type: ignore

    end_time = None
    if end_time_str:
        try:
            end_time = datetime.fromisoformat(end_time_str)
        except ValueError:
            print_error(f"Invalid end time: {end_time_str}")  # type: ignore
            raise click.Exit(1) from None  # type: ignore

    enabled = enable if enable is not None else None

    try:
        window = manager.update_window(
            window_id,
            name=name,
            start_time=start_time,
            end_time=end_time,
            description=description,
            enabled=enabled,
        )

        print_success(f"Updated maintenance window: {window.name}")
        key_value("ID", str(window.id))
        key_value("Status", "enabled" if window.enabled else "disabled")

    except Exception as e:
        print_error(f"Failed to update maintenance: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="delete")
@click.argument("window_id", type=int)
@click.confirmation_option(
    prompt="Are you sure you want to delete this maintenance window?",
)
@click.pass_context
def maintenance_delete(ctx: click.Context, window_id: int) -> None:
    """Delete a maintenance window."""
    manager = get_manager(ctx)

    try:
        manager.delete_window(window_id)
        print_success(f"Deleted maintenance window {window_id}")
    except Exception as e:
        print_error(f"Failed to delete maintenance window: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="enable")
@click.argument("window_id", type=int)
@click.pass_context
def maintenance_enable(ctx: click.Context, window_id: int) -> None:
    """Enable a maintenance window."""
    manager = get_manager(ctx)

    try:
        window = manager.update_window(window_id, enabled=True)
        print_success(f"Enabled maintenance window: {window.name}")
    except Exception as e:
        print_error(f"Failed to enable maintenance window: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="disable")
@click.argument("window_id", type=int)
@click.pass_context
def maintenance_disable(ctx: click.Context, window_id: int) -> None:
    """Disable a maintenance window."""
    manager = get_manager(ctx)

    try:
        window = manager.update_window(window_id, enabled=False)
        print_success(f"Disabled maintenance window: {window.name}")
    except Exception as e:
        print_error(f"Failed to disable maintenance window: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="cleanup")
@click.option(
    "--before",
    "-b",
    help="Delete windows ending before this time (ISO format)",
)
@click.pass_context
def maintenance_cleanup(ctx: click.Context, before: str | None) -> None:
    """Clean up expired maintenance windows."""
    manager = get_manager(ctx)

    before_dt = None
    if before:
        try:
            before_dt = datetime.fromisoformat(before)
        except ValueError:
            print_error(f"Invalid time: {before}")  # type: ignore
            raise click.Exit(1) from None  # type: ignore

    try:
        deleted = manager.cleanup_expired(before_dt)
        if deleted > 0:
            print_success(f"Cleaned up {deleted} expired maintenance windows")
        else:
            print_info("No expired maintenance windows found")
    except Exception as e:
        print_error(f"Failed to cleanup: {e}")  # type: ignore
        raise click.Exit(1) from None  # type: ignore


@maintenance_cli.command(name="check")
@click.pass_context
def maintenance_check(ctx: click.Context) -> None:
    """Check if currently in maintenance mode."""
    manager = get_manager(ctx)

    if manager.is_in_maintenance():
        state = manager.get_maintenance_state()
        print_warning("🔧 IN MAINTENANCE MODE")
        if state.active_window:
            click.echo(f"Window: {state.active_window.name}")
            if state.maintenance_end:
                remaining = state.maintenance_end - datetime.utcnow()
                click.echo(f"Remaining: {remaining}")
        raise click.Exit(1)  # type: ignore
    else:
        print_success("✅ Not in maintenance mode")


def _parse_time(time_str: str) -> datetime | None:
    """Parse a time string into a datetime.

    Supports:
    - ISO format (2024-01-15T10:00:00)
    - 'now' - current time
    - 'tomorrow' - tomorrow at midnight
    - 'in X minutes/hours/days'
    """
    time_str = time_str.lower().strip()

    now = datetime.utcnow()

    if time_str == "now":
        return now

    if time_str == "tomorrow":
        return now.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)

    # Try ISO format
    try:
        return datetime.fromisoformat(time_str)
    except ValueError:
        pass

    # Try relative time: "in X minutes/hours/days"
    if time_str.startswith("in "):
        parts = time_str[3:].split()
        if len(parts) == 2:
            try:
                amount = int(parts[0])
                unit = parts[1].rstrip("s")  # Remove trailing 's'

                if unit == "minute":
                    return now + timedelta(minutes=amount)
                elif unit == "hour":
                    return now + timedelta(hours=amount)
                elif unit == "day":
                    return now + timedelta(days=amount)
            except ValueError:
                pass

    return None


def register_commands(cli: click.Group) -> None:
    """Register maintenance commands with the CLI."""
    cli.add_command(maintenance_cli)
