"""AWS CLI connector for AiCippy.

Provides access to AWS services through the AWS CLI.
"""

from __future__ import annotations

import json
import shlex
import shutil
from typing import Any

from aicippy.connectors.base import (
    BaseConnector,
    ConnectorConfig,
    ConnectorStatus,
    ToolResult,
)
from aicippy.utils.logging import get_logger

logger = get_logger(__name__)

# AWS CLI subcommand patterns that are destructive and blocked by default
DANGEROUS_PATTERNS: frozenset[str] = frozenset({
    "delete-bucket",
    "delete-db-instance",
    "delete-db-cluster",
    "delete-stack",
    "delete-table",
    "delete-function",
    "delete-cluster",
    "delete-vpc",
    "delete-security-group",
    "terminate-instances",
    "deregister-image",
    "delete-snapshot",
    "delete-volume",
    "release-address",
    "delete-nat-gateway",
    "delete-internet-gateway",
    "delete-subnet",
    "delete-route-table",
    "delete-log-group",
    "delete-repository",
    "put-bucket-policy",
    "put-role-policy",
    "delete-role",
    "delete-user",
    "detach-role-policy",
    "delete-access-key",
})

# Full AWS CLI command prefixes that are completely blocked
BLOCKED_COMMANDS: frozenset[str] = frozenset({
    "aws iam delete-account-alias",
    "aws iam create-login-profile",
    "aws iam update-login-profile",
    "aws organizations leave-organization",
    "aws organizations delete-organization",
})


class AWSConnector(BaseConnector):
    """AWS CLI connector.

    Provides access to AWS services with safety validations
    and credential chain support.
    """

    name = "aws"
    description = "AWS CLI operations with full service coverage"
    version = "1.0.0"

    def __init__(self, config: ConnectorConfig | None = None) -> None:
        """Initialize AWS connector."""
        super().__init__(config)
        self._aws_path: str | None = None

    async def check_availability(self) -> bool:
        """Check if AWS CLI is available.

        Returns:
            True if AWS CLI is installed and configured.

        """
        self._aws_path = shutil.which("aws")
        if not self._aws_path:
            self._status = ConnectorStatus.UNAVAILABLE
            self._last_error = "AWS CLI not found in PATH"
            return False

        # Check for credentials
        result = await self._run_command(
            [self._aws_path, "sts", "get-caller-identity"],
            timeout=10,
        )

        if result.success:
            self._status = ConnectorStatus.AVAILABLE
            return True
        self._status = ConnectorStatus.ERROR
        self._last_error = "AWS credentials not configured"
        return False

    async def validate_command(self, command: str) -> tuple[bool, str]:
        """Validate an AWS CLI command.

        Checks for dangerous AWS operations that could cause
        data loss or infrastructure destruction.

        Args:
            command: Command to validate.

        Returns:
            Tuple of (is_valid, error_message).

        """
        # Check for shell injection at the base level
        if self._has_shell_injection(command):
            return False, "Shell injection characters detected in AWS command"

        # Check base-level dangerous command patterns
        is_dangerous, reason = self._is_dangerous_command(command)
        if is_dangerous:
            return False, reason

        cmd_lower = command.strip().lower()

        # Check fully blocked commands
        for blocked in BLOCKED_COMMANDS:
            if cmd_lower.startswith(blocked):
                logger.warning("aws_blocked_command", command=command[:100])
                return False, f"Blocked AWS command: {blocked}"

        # Check for dangerous subcommand patterns
        for pattern in DANGEROUS_PATTERNS:
            if pattern in cmd_lower:
                logger.warning(
                    "aws_dangerous_pattern",
                    pattern=pattern,
                    command=command[:100],
                )
                return False, f"Dangerous AWS operation blocked: {pattern}"

        # Check allowlist/blocklist from configuration
        is_allowed, error = self._is_command_allowed(command)
        if not is_allowed:
            return False, error

        return True, ""

    async def execute(self, command: str, **_kwargs: Any) -> ToolResult:  # noqa: ANN401
        """Execute an AWS CLI command.

        Args:
            command: AWS CLI command (starting with 'aws').
            **_kwargs: Additional arguments.

        Returns:
            ToolResult with command output.

        """
        # Validate
        is_valid, error = await self.validate_command(command)
        if not is_valid:
            return ToolResult.error_result(error)

        # Check availability
        if not self._aws_path:
            await self.check_availability()

        if not self.is_available:
            return ToolResult.error_result(self._last_error or "AWS CLI not available")

        # Parse command into arguments
        args = shlex.split(command)

        # Add output format if not specified
        if "--output" not in args and "-o" not in args:
            args.extend(["--output", "json"])

        # Execute
        logger.info("aws_command_executing", command=command[:100])
        result = await self._run_command(args)

        if result.success:
            logger.info("aws_command_success", execution_time_ms=result.execution_time_ms)
        else:
            logger.warning(
                "aws_command_failed",
                error=result.error,
                execution_time_ms=result.execution_time_ms,
            )

        return result

    async def get_current_identity(self) -> dict[str, Any]:
        """Get current AWS identity.

        Returns:
            Dictionary with account, ARN, and user ID.

        """
        result = await self.execute("aws sts get-caller-identity")
        if result.success:
            try:
                return json.loads(result.output)
            except json.JSONDecodeError:
                return {}
        return {}

    async def list_regions(self) -> list[str]:
        """List available AWS regions.

        Returns:
            List of region names.

        """
        result = await self.execute("aws ec2 describe-regions --query 'Regions[].RegionName'")
        if result.success:
            try:
                return json.loads(result.output)
            except json.JSONDecodeError:
                return []
        return []

