"""
ID Wispera Provisioning Module Types
Types for programmatic credential creation through vendor APIs
"""

from enum import Enum
from typing import Any, Literal, Optional, Union

from pydantic import BaseModel, ConfigDict, Field

from id_wispera.types import VisaType, CredentialType, Platform, DelegationHop


# ============================================================================
# Provider Registry
# ============================================================================

class ProvisioningProvider(str, Enum):
    """Supported provisioning providers"""
    OPENAI = "openai"
    AWS = "aws"
    GOOGLE_CLOUD = "google-cloud"
    AZURE_ENTRA = "azure-entra"
    GITHUB = "github"
    TWILIO = "twilio"
    SENDGRID = "sendgrid"
    ANTHROPIC = "anthropic"  # Partial support: list/update/disable only, no create


class ProviderCapabilities(BaseModel):
    """Provider capability flags"""
    can_create: bool = Field(alias="canCreate")
    can_configure_permissions: bool = Field(alias="canConfigurePermissions")
    can_rotate: bool = Field(alias="canRotate")
    can_revoke: bool = Field(alias="canRevoke")
    can_list: bool = Field(alias="canList")
    supports_expiry: bool = Field(alias="supportsExpiry")
    supports_scoped_keys: bool = Field(alias="supportsScopedKeys")
    model_config = ConfigDict(populate_by_name=True)


# ============================================================================
# Authentication
# ============================================================================

# ProviderAuth is a dict-based type union.
# Use the 'type' key to distinguish: 'api-key', 'basic', 'aws-sigv4',
# 'oauth2', 'jwt', 'service-account'
ProviderAuth = dict[str, Any]


# ============================================================================
# Provider-Specific Configs
# ============================================================================

class OpenAIConfig(BaseModel):
    """OpenAI provider configuration"""
    provider: Literal["openai"] = "openai"
    organization_id: str = Field(alias="organizationId")
    project_id: Optional[str] = Field(None, alias="projectId")
    key_type: str = Field(alias="keyType")  # 'admin' or 'service-account'
    model_config = ConfigDict(populate_by_name=True)


class AWSConfig(BaseModel):
    """AWS provider configuration"""
    provider: Literal["aws"] = "aws"
    user_name: Optional[str] = Field(None, alias="userName")
    role_arn: Optional[str] = Field(None, alias="roleArn")
    session_name: Optional[str] = Field(None, alias="sessionName")
    duration_seconds: Optional[int] = Field(None, alias="durationSeconds")
    external_id: Optional[str] = Field(None, alias="externalId")
    model_config = ConfigDict(populate_by_name=True)


class GoogleCloudConfig(BaseModel):
    """Google Cloud provider configuration"""
    provider: Literal["google-cloud"] = "google-cloud"
    project_id: str = Field(alias="projectId")
    key_type: str = Field(alias="keyType")  # 'api-key' or 'service-account-key'
    service_account_email: Optional[str] = Field(None, alias="serviceAccountEmail")
    api_targets: Optional[list[str]] = Field(None, alias="apiTargets")
    allowed_ips: Optional[list[str]] = Field(None, alias="allowedIps")
    model_config = ConfigDict(populate_by_name=True)


class AzureEntraConfig(BaseModel):
    """Azure Entra ID provider configuration"""
    provider: Literal["azure-entra"] = "azure-entra"
    tenant_id: str = Field(alias="tenantId")
    mode: str  # 'create-app' or 'add-secret'
    application_id: Optional[str] = Field(None, alias="applicationId")
    display_name: Optional[str] = Field(None, alias="displayName")
    secret_expiry_days: Optional[int] = Field(None, alias="secretExpiryDays")
    model_config = ConfigDict(populate_by_name=True)


class GitHubConfig(BaseModel):
    """GitHub provider configuration"""
    provider: Literal["github"] = "github"
    installation_id: int = Field(alias="installationId")
    repository_ids: Optional[list[int]] = Field(None, alias="repositoryIds")
    repositories: Optional[list[str]] = None
    model_config = ConfigDict(populate_by_name=True)


class TwilioConfig(BaseModel):
    """Twilio provider configuration"""
    provider: Literal["twilio"] = "twilio"
    account_sid: str = Field(alias="accountSid")
    key_type: str = Field(alias="keyType")  # 'standard' or 'restricted'
    friendly_name: Optional[str] = Field(None, alias="friendlyName")
    model_config = ConfigDict(populate_by_name=True)


class SendGridConfig(BaseModel):
    """SendGrid provider configuration"""
    provider: Literal["sendgrid"] = "sendgrid"


class AnthropicConfig(BaseModel):
    """Anthropic provider configuration (management only, no key creation)"""
    provider: Literal["anthropic"] = "anthropic"
    workspace_id: Optional[str] = Field(None, alias="workspaceId")
    model_config = ConfigDict(populate_by_name=True)


# Union type for provider-specific configs
ProviderSpecificConfig = Union[
    OpenAIConfig,
    AWSConfig,
    GoogleCloudConfig,
    AzureEntraConfig,
    GitHubConfig,
    TwilioConfig,
    SendGridConfig,
    AnthropicConfig,
]


# ============================================================================
# Provider-Specific Permissions
# ============================================================================

class OpenAIPermissions(BaseModel):
    """OpenAI permissions"""
    provider: Literal["openai"] = "openai"
    level: str  # 'all', 'read-only', or 'restricted'
    endpoints: Optional[dict[str, str]] = None  # endpoint -> 'read'|'write'|'none'


class AWSPermissions(BaseModel):
    """AWS permissions"""
    provider: Literal["aws"] = "aws"
    session_policy: Optional[str] = Field(None, alias="sessionPolicy")
    policy_arns: Optional[list[str]] = Field(None, alias="policyArns")
    tags: Optional[dict[str, str]] = None
    model_config = ConfigDict(populate_by_name=True)


class GoogleCloudPermissions(BaseModel):
    """Google Cloud permissions"""
    provider: Literal["google-cloud"] = "google-cloud"
    roles: Optional[list[str]] = None
    conditions: Optional[list[dict[str, str]]] = None


class AzureEntraPermissions(BaseModel):
    """Azure Entra permissions"""
    provider: Literal["azure-entra"] = "azure-entra"
    graph_permissions: Optional[list[str]] = Field(None, alias="graphPermissions")
    rbac_roles: Optional[list[dict[str, str]]] = Field(None, alias="rbacRoles")
    model_config = ConfigDict(populate_by_name=True)


class GitHubPermissions(BaseModel):
    """GitHub permissions"""
    provider: Literal["github"] = "github"
    permissions: Optional[dict[str, str]] = None


class TwilioPermissions(BaseModel):
    """Twilio permissions"""
    provider: Literal["twilio"] = "twilio"
    policy: Optional[dict[str, Any]] = None


class SendGridPermissions(BaseModel):
    """SendGrid permissions"""
    provider: Literal["sendgrid"] = "sendgrid"
    scopes: list[str]


ProviderPermissions = Union[
    OpenAIPermissions,
    AWSPermissions,
    GoogleCloudPermissions,
    AzureEntraPermissions,
    GitHubPermissions,
    TwilioPermissions,
    SendGridPermissions,
]


# ============================================================================
# Provisioning Request
# ============================================================================

class ProvisioningRequest(BaseModel):
    """Request to provision a new credential"""
    provider: ProvisioningProvider
    name: str
    human_owner: str = Field(alias="humanOwner")
    agent_id: Optional[str] = Field(None, alias="agentId")
    config: dict[str, Any]  # Provider-specific config as dict
    permissions: Optional[dict[str, Any]] = None
    expires_in: Optional[int] = Field(None, alias="expiresIn")  # seconds
    tags: Optional[list[str]] = None
    notes: Optional[str] = None
    delegation_chain: Optional[list[DelegationHop]] = Field(None, alias="delegationChain")
    model_config = ConfigDict(populate_by_name=True)


# ============================================================================
# Provisioning Results
# ============================================================================

class ProvisioningResult(BaseModel):
    """Result of a provisioning operation"""
    success: bool
    credential_value: Optional[str] = Field(None, alias="credentialValue")
    secondary_value: Optional[str] = Field(None, alias="secondaryValue")
    provider_key_id: Optional[str] = Field(None, alias="providerKeyId")
    metadata: Optional[dict[str, Any]] = None
    expires_at: Optional[str] = Field(None, alias="expiresAt")
    passport_input: Optional[dict[str, Any]] = Field(None, alias="passportInput")
    error: Optional[dict[str, Any]] = None
    model_config = ConfigDict(populate_by_name=True)


class RotationResult(BaseModel):
    """Credential rotation result"""
    new_credential: ProvisioningResult = Field(alias="newCredential")
    old_key_id: str = Field(alias="oldKeyId")
    recommended_revocation_delay: int = Field(alias="recommendedRevocationDelay")  # seconds
    model_config = ConfigDict(populate_by_name=True)
