"""
Runtime secrets resolution service.

Single Responsibility: Resolve CloudZero API tokens from environment or AWS Secrets Manager.
"""

import os
from typing import Optional

import boto3
from botocore.exceptions import ClientError


class SecretsResolver:
    """
    Resolves CloudZero API tokens with fallback strategy.

    Resolution order:
    1. Environment variables (CLI and ECS task definition)
    2. AWS Secrets Manager (ECS dynamic retrieval)
    """

    def __init__(
        self,
        environment: str = "dev",
        region: str = "us-east-1",
        secrets_client: Optional[any] = None,
    ):
        """
        Initialize secrets resolver.

        Args:
            environment: Environment name (dev, staging, prod)
            region: AWS region for Secrets Manager
            secrets_client: Optional boto3 client (for testing)
        """
        self.environment = environment
        self.region = region
        self._secrets_client = secrets_client

    @property
    def secrets_client(self):
        """Lazy-load Secrets Manager client."""
        if self._secrets_client is None:
            self._secrets_client = boto3.client(
                "secretsmanager", region_name=self.region
            )
        return self._secrets_client

    def get_org_api_key(self, org_name: str) -> str:
        """
        Get CloudZero API token for organization.

        Args:
            org_name: Organization name (e.g., "DemoTest")

        Returns:
            API token string

        Raises:
            ValueError: If token not found in any source
        """
        # Try environment variable first (CLI or task definition)
        token = self._get_from_environment(org_name)
        if token:
            return token

        # Try Secrets Manager (ECS dynamic retrieval)
        token = self._get_from_secrets_manager(org_name)
        if token:
            return token

        # No token found
        raise ValueError(
            f"No CloudZero API key found for organization '{org_name}'. "
            f"Please set CZ_ORG_API_KEY_{org_name.upper()} in ~/.czbg/.env "
            f"or create secret in AWS Secrets Manager"
        )

    def get_connection_config(self) -> dict:
        """
        Get CloudZero connection configuration (IAM role and external ID).

        Returns:
            Dict with aws_iam_role_arn and aws_iam_external_id

        Raises:
            ValueError: If config not found in any source
        """
        import json

        # Try environment variables first
        role_arn = os.getenv("AWS_IAM_ROLE_ARN")
        external_id = os.getenv("AWS_IAM_EXTERNAL_ID")

        if role_arn and external_id:
            return {
                "aws_iam_role_arn": role_arn,
                "aws_iam_external_id": external_id
            }

        # Try Secrets Manager
        secret_name = f"czbg/{self.environment}/cloudzero/connection-config"
        try:
            response = self.secrets_client.get_secret_value(SecretId=secret_name)
            secret_string = response.get("SecretString")
            if secret_string:
                return json.loads(secret_string)
        except ClientError as e:
            error_code = e.response.get("Error", {}).get("Code")
            if error_code != "ResourceNotFoundException":
                raise ValueError(
                    f"Failed to retrieve connection config: {error_code}"
                ) from e

        # No config found
        raise ValueError(
            "No CloudZero connection configuration found. "
            "Please set AWS_IAM_ROLE_ARN and AWS_IAM_EXTERNAL_ID in ~/.czbg/.env "
            "or create secret czbg/dev/cloudzero/connection-config in AWS Secrets Manager"
        )

    def _get_from_environment(self, org_name: str) -> Optional[str]:
        """
        Get token from environment variables.

        Checks:
        1. CZ_ORG_API_KEY_{ORG_NAME} (org-specific)
        2. CZ_ORG_API_KEY (generic fallback)
        """
        org_key_var = f"CZ_ORG_API_KEY_{org_name.upper()}"
        token = os.getenv(org_key_var)
        if token:
            return token

        # Generic fallback
        return os.getenv("CZ_ORG_API_KEY")

    def _get_from_secrets_manager(self, org_name: str) -> Optional[str]:
        """
        Get token from AWS Secrets Manager.

        Secret name format: czbg/{env}/cloudzero/{org_name}
        """
        secret_name = f"czbg/{self.environment}/cloudzero/{org_name.upper()}"

        try:
            response = self.secrets_client.get_secret_value(SecretId=secret_name)
            return response.get("SecretString")
        except ClientError as e:
            error_code = e.response.get("Error", {}).get("Code")
            if error_code == "ResourceNotFoundException":
                return None
            # Re-raise other errors (AccessDenied, etc.)
            raise ValueError(
                f"Failed to retrieve secret for {org_name}: {error_code}"
            ) from e
