"""AWS CloudFormation StackSet management."""

import time
from typing import Any, Optional

from botocore.exceptions import ClientError

from ai_org.core.aws_client import AWSClient


class StackSetManager:
    """Manages AWS CloudFormation StackSets."""

    def __init__(self, profile: Optional[str] = None, region: Optional[str] = None):
        """Initialize StackSet manager.

        Args:
            profile: AWS profile name
            region: AWS region
        """
        self.aws = AWSClient(profile, region)
        self.cfn_client = self.aws.client("cloudformation")

    def get_deployment_status(
        self, account_id: str, stackset_name: Optional[str] = None
    ) -> list[dict[str, Any]]:
        """Get StackSet deployment status for an account.

        Args:
            account_id: AWS account ID
            stackset_name: Specific StackSet name (optional)

        Returns:
            List of status dictionaries
        """
        try:
            statuses = []

            if stackset_name:
                # Get status for specific StackSet
                stacksets = [stackset_name]
            else:
                # List all StackSets
                stacksets = self._list_all_stacksets()

            for name in stacksets:
                try:
                    # Get stack instance status
                    response = self.cfn_client.describe_stack_instance(
                        StackSetName=name,
                        StackInstanceAccount=account_id,
                        StackInstanceRegion=self.aws.region,
                    )
                    instance = response["StackInstance"]
                    statuses.append(
                        {
                            "StackSetName": name,
                            "Status": instance.get("Status", "UNKNOWN"),
                            "StatusReason": instance.get("StatusReason", ""),
                            "DriftStatus": instance.get("DriftStatus", "NOT_CHECKED"),
                        }
                    )
                except ClientError as e:
                    if e.response["Error"]["Code"] == "StackInstanceNotFoundException":
                        # Stack instance doesn't exist for this account
                        statuses.append(
                            {
                                "StackSetName": name,
                                "Status": "NOT_DEPLOYED",
                                "StatusReason": "Stack instance not found",
                                "DriftStatus": "NOT_CHECKED",
                            }
                        )
                    else:
                        raise

            return statuses

        except ClientError as e:
            raise Exception(self.aws.handle_error(e, "Failed to get deployment status")) from e

    def wait_for_deployments(
        self,
        account_id: str,
        stackset_name: Optional[str] = None,
        timeout: int = 300,
    ) -> bool:
        """Wait for StackSet deployments to complete.

        Args:
            account_id: AWS account ID
            stackset_name: Specific StackSet name (optional)
            timeout: Maximum wait time in seconds

        Returns:
            True if all deployments succeeded, False otherwise
        """
        start_time = time.time()
        check_interval = 10

        while time.time() - start_time < timeout:
            statuses = self.get_deployment_status(account_id, stackset_name)

            # Check if all are in a terminal state
            all_complete = True
            all_success = True

            for status in statuses:
                state = status["Status"]
                if state in ["PENDING", "RUNNING", "OUTDATED"]:
                    all_complete = False
                    break
                if state not in ["CURRENT", "SUCCEEDED"]:
                    all_success = False

            if all_complete:
                return all_success

            time.sleep(check_interval)

        return False  # Timed out

    def list_stacksets(self) -> list[dict[str, Any]]:
        """List all StackSets in the organization.

        Returns:
            List of StackSet dictionaries
        """
        try:
            stacksets = []
            paginator = self.cfn_client.get_paginator("list_stack_sets")

            for page in paginator.paginate(Status="ACTIVE"):
                for summary in page.get("Summaries", []):
                    stacksets.append(
                        {
                            "StackSetName": summary["StackSetName"],
                            "Status": summary.get("Status", "UNKNOWN"),
                            "AutoDeployment": "Enabled"
                            if summary.get("AutoDeployment", {}).get("Enabled")
                            else "Disabled",
                            "Capabilities": ", ".join(summary.get("Capabilities", [])),
                            "DriftStatus": summary.get("DriftStatus", "NOT_CHECKED"),
                        }
                    )

            return stacksets

        except ClientError as e:
            raise Exception(self.aws.handle_error(e, "Failed to list StackSets")) from e

    def _list_all_stacksets(self) -> list[str]:
        """List all StackSet names.

        Returns:
            List of StackSet names
        """
        stacksets = []
        paginator = self.cfn_client.get_paginator("list_stack_sets")

        for page in paginator.paginate(Status="ACTIVE"):
            for summary in page.get("Summaries", []):
                stacksets.append(summary["StackSetName"])

        return stacksets

    def get_stackset_operations(self, stackset_name: str, limit: int = 10) -> list[dict[str, Any]]:
        """Get recent operations for a StackSet.

        Args:
            stackset_name: StackSet name
            limit: Maximum number of operations to return

        Returns:
            List of operation dictionaries
        """
        try:
            response = self.cfn_client.list_stack_set_operations(
                StackSetName=stackset_name,
                MaxResults=limit,
            )

            operations = []
            for op in response.get("Summaries", []):
                operations.append(
                    {
                        "OperationId": op["OperationId"],
                        "Action": op.get("Action", "UNKNOWN"),
                        "Status": op.get("Status", "UNKNOWN"),
                        "CreationTime": op.get("CreationTimestamp"),
                        "EndTime": op.get("EndTimestamp"),
                    }
                )

            return operations

        except ClientError as e:
            raise Exception(
                self.aws.handle_error(e, f"Failed to get operations for {stackset_name}")
            ) from e
