"""
vr deploy command - Deploy a function to an environment.
"""

import sys
from pathlib import Path
from typing import Optional

import questionary
import typer

from vr_cli.utils.utils import (
    console,
    make_request,
    print_success,
    print_error,
    print_info,
    print_warning,
    confirm,
    calculate_project_checksum,
)
from vr_cli.utils.agent_lock import load_agent_lock
from vr_cli.entities.agent_environment import AgentEnvironment, AgentEnvironmentRepository
from vr_cli.commands.validate import (
    run_project_validation,
)


def check_unpushed_changes(project_dir: Path, agent_lock: dict) -> bool:
    """
    Check if local project files have changed since the last push by comparing checksums.
    Returns True if safe to proceed, False if user aborts.
    """
    stored_checksum = agent_lock.get("checksum")
    if not stored_checksum:
        # No checksum stored (older push) — skip the check
        return True

    current_checksum = calculate_project_checksum(str(project_dir))

    if current_checksum == stored_checksum:
        return True

    console.print()
    print_warning("Local project files have changed since the last push.")
    print_info("Run 'vr push' first to ensure the deployed code matches your local changes.")

    if not sys.stdin.isatty():
        print_error("Aborting deploy due to unpushed changes in non-interactive mode.")
        print_info("Push your changes first, or use --yes (-y) to skip this check.")
        return False

    return confirm("Continue deploying anyway?", default=False)


def run_deploy_validation(project_dir: Path) -> bool:
    """Run validation checks before deploying. Returns True if valid."""
    result = run_project_validation(project_dir, include_handler=False)

    if not result.is_valid:
        console.print()
        console.print("[bold red]Validation failed:[/bold red]")
        for check, error in result.failed:
            console.print(f"  [red]✗[/red] {check}: {error}")
        console.print()
        return False

    return True


def resolve_environment(agent_id: str, name_or_id: str) -> Optional[AgentEnvironment]:
    """Resolve an environment name or ID to an AgentEnvironment object."""
    repo = AgentEnvironmentRepository(agent_id)
    env = repo.get_by_name_or_id(name_or_id)

    if not env:
        print_error(f"Environment '{name_or_id}' not found")
        print_info("Use 'vr get environments' to list available environments")

    return env


def prompt_for_environment(agent_id: str) -> Optional[AgentEnvironment]:
    """Prompt user to select an environment from available options on the agent."""
    # Check if stdin is a TTY - interactive prompts require a terminal
    if not sys.stdin.isatty():
        print_error("Cannot prompt for environment: not running in an interactive terminal")
        print_info("Specify the environment as an argument: vr deploy <environment>")
        return None

    repo = AgentEnvironmentRepository(agent_id)
    environments = repo.get()

    if not environments:
        print_error("No environments found for this agent")
        print_info("Create an environment in the VoiceRun dashboard first")
        return None

    # Build choices for questionary select
    choices = []
    for env in environments:
        # Format: "name (phone, stt_model)" for display
        label_parts = [env.name or "unnamed"]
        details = []
        if env.phone_number:
            details.append(env.phone_number)
        if env.stt_model:
            details.append(env.stt_model)
        if details:
            label_parts.append(f"({', '.join(details)})")

        choices.append(questionary.Choice(
            title=" ".join(label_parts),
            value=env,
        ))

    # Use questionary for interactive selection
    selected = questionary.select(
        "Select an environment to deploy to:",
        choices=choices,
    ).ask()

    if selected is None:
        # User cancelled (Ctrl+C)
        return None

    return selected


def deploy(
    environment: Optional[str] = typer.Argument(
        None,
        help="Environment to deploy to (e.g., development, production). If not specified, you'll be prompted to select.",
    ),
    yes: bool = typer.Option(
        False,
        "--yes",
        "-y",
        help="Skip confirmation prompt.",
    ),
):
    """
    Deploy a function to an environment.

    This command deploys the latest pushed function version to the
    specified environment.

    Examples:
        vr deploy                              # Select environment interactively
        vr deploy development                  # Deploy to development
        vr deploy production --yes             # Deploy to production without confirmation
    """
    project_dir = Path.cwd()
    voicerun_dir = project_dir / ".voicerun"

    # Check if this is a voicerun project
    if not voicerun_dir.exists():
        print_error("Not a voicerun project (.voicerun directory not found)")
        print_info("Run 'vr init' to create a new project")
        raise typer.Exit(1)

    # Load agent lock to get agent ID and function ID
    agent_lock = load_agent_lock(voicerun_dir)
    if not agent_lock or not agent_lock.get("id"):
        print_error("No agent.lock found. Run 'vr push' first to create an agent.")
        raise typer.Exit(1)

    agent_id = agent_lock.get("id")
    function_id = agent_lock.get("functionId")
    if not function_id:
        print_error("No functionId found in agent.lock. Run 'vr push' to update.")
        raise typer.Exit(1)

    # Check for unpushed changes (skip if --yes)
    if not yes and not check_unpushed_changes(project_dir, agent_lock):
        raise typer.Exit(1)

    # Validate project
    print_info("Validating project...")
    if not run_deploy_validation(project_dir):
        raise typer.Exit(1)

    # Resolve environment
    if environment:
        env = resolve_environment(agent_id, environment)
    else:
        env = prompt_for_environment(agent_id)

    if not env:
        raise typer.Exit(1)

    # Show summary
    console.print()
    console.print("[bold]Deploy Summary:[/bold]")
    console.print(f"  Agent ID:    [cyan]{agent_id[:8]}...[/cyan]")
    console.print(f"  Environment: [yellow]{env.name}[/yellow]")
    console.print(f"  Function ID: [cyan]{function_id[:8]}...[/cyan]")
    console.print()

    # Confirm deployment
    if not yes:
        if not sys.stdin.isatty():
            print_error("Cannot prompt for confirmation: not running in an interactive terminal")
            print_info("Use --yes (-y) flag to skip confirmation in non-interactive mode")
            raise typer.Exit(1)
        if not confirm(f"Deploy to {env.name}?", default=True):
            print_info("Aborted")
            raise typer.Exit(0)

    # Deploy function to environment
    print_info("Deploying...")

    repo = AgentEnvironmentRepository(agent_id)
    result = repo.deploy_function(env.id, function_id)

    if not result:
        print_error("Failed to deploy")
        raise typer.Exit(1)

    console.print()
    print_success(f"Deployed to {env.name}!")
