"""
Command-line interface for kvenv.

Provides the main entry point for running commands with environment
variables resolved from Azure Key Vault.
"""

from __future__ import annotations

import os
import sys
from pathlib import Path

import click

from .keyvault import (
    AzureCliNotFoundError,
    InvalidSecretNameError,
    InvalidVaultNameError,
    KeyVaultAccessError,
    KeyVaultError,
    check_az_cli,
    fetch_secret,
)
from .parser import EnvParseError, parse_env_file


def print_error(message: str) -> None:
    """Print an error message to stderr."""
    click.echo(click.style(f"Error: {message}", fg="red"), err=True)


def print_warning(message: str) -> None:
    """Print a warning message to stderr."""
    click.echo(click.style(f"Warning: {message}", fg="yellow"), err=True)


HELP_TEXT = """
Run commands with environment variables resolved from Azure Key Vault.

\b
Examples:
  # Uses .env and default vault from KEYVAULT
  KEYVAULT=my-kv kvenv -- npm run dev

  # Uses .env.ref, default vault via -v
  kvenv -e .env.ref -v my-kv -- npm run dev

  # Per-secret vault override inside file
  DATABASE_URL=kv://some-kv/DATABASE-URL

\b
.env format:
  - Lines: KEY=VALUE
  - Comments: lines starting with # (optionally preceded by whitespace)
  - Blank lines allowed
  - Optional leading "export " supported
  - Quoted values supported: "..." or '...'
  - VALUE may contain '='

\b
Key Vault references:
  VALUE = kv://SECRET_NAME
  VALUE = kv://VAULT_NAME/SECRET_NAME

Non kv:// values are passed through unchanged.

\b
Requirements:
  - Azure CLI installed
  - You are authenticated: az login
  - Access to Key Vault secrets: get permission
"""


@click.command(help=HELP_TEXT, context_settings={"ignore_unknown_options": True})
@click.option(
    "-e",
    "--env-file",
    default=".env",
    type=click.Path(exists=False),
    help="Path to the environment file (default: .env)",
)
@click.option(
    "-v",
    "--vault",
    default=None,
    envvar="KEYVAULT",
    help="Default Key Vault name (can also use KEYVAULT env var)",
)
@click.argument("command", nargs=-1, required=True)
@click.pass_context
def main(
    ctx: click.Context,
    env_file: str,
    vault: str | None,
    command: tuple[str, ...],
) -> None:
    """
    Run a command with environment variables resolved from Azure Key Vault.
    """
    # Validate env file exists
    env_path = Path(env_file)
    if not env_path.exists():
        print_error(f"Environment file not found: {env_file}")
        sys.exit(1)

    # Validate command is provided
    if not command:
        print_error("Missing command. Provide command after -- separator.")
        sys.exit(1)

    # Filter out "--" if present at the start of command
    command_list = list(command)
    if command_list and command_list[0] == "--":
        command_list = command_list[1:]

    if not command_list:
        print_error("Missing command. Provide command after -- separator.")
        sys.exit(1)

    # Track if we need az CLI (only check if we have kv:// refs)
    has_kv_refs = False
    env_vars: dict[str, str] = {}

    try:
        # First pass: parse all entries and check for kv:// refs
        entries = list(parse_env_file(env_path, vault))

        for entry in entries:
            if entry.is_keyvault_ref:
                has_kv_refs = True
                break

        # Check az CLI if we have kv:// refs
        if has_kv_refs:
            check_az_cli()

        # Process entries
        for entry in entries:
            if entry.is_keyvault_ref:
                # Check vault is available
                if not entry.vault_name:
                    print_error(
                        f"Default Key Vault not set, but reference requires it: "
                        f"{entry.value} (line {entry.line_number})\n"
                        "Set KEYVAULT env var or pass -v/--vault."
                    )
                    sys.exit(1)

                # Fetch secret from Key Vault
                try:
                    resolved = fetch_secret(entry.vault_name, entry.secret_name)
                    env_vars[entry.key] = resolved
                except InvalidVaultNameError as e:
                    print_error(f"Line {entry.line_number}: {e}")
                    sys.exit(1)
                except InvalidSecretNameError as e:
                    print_error(f"Line {entry.line_number}: {e}")
                    sys.exit(1)
                except KeyVaultAccessError as e:
                    print_error(f"Line {entry.line_number}: {e}")
                    sys.exit(1)
            else:
                env_vars[entry.key] = entry.value

    except EnvParseError as e:
        print_error(str(e))
        sys.exit(1)
    except AzureCliNotFoundError as e:
        print_error(str(e))
        sys.exit(1)
    except KeyVaultError as e:
        print_error(str(e))
        sys.exit(1)

    # Merge with current environment and add parsed vars
    new_env = os.environ.copy()
    new_env.update(env_vars)

    # Execute command with injected environment
    # Using os.execvpe to replace the current process (like exec in bash)
    try:
        os.execvpe(command_list[0], command_list, new_env)
    except FileNotFoundError:
        print_error(f"Command not found: {command_list[0]}")
        sys.exit(127)
    except PermissionError:
        print_error(f"Permission denied: {command_list[0]}")
        sys.exit(126)
    except OSError as e:
        print_error(f"Failed to execute command: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
