"""
Credential model for secure storage of authentication credentials.

This model stores various types of credentials (passwords, API keys, OAuth tokens, etc.)
with encryption for sensitive fields.
"""

from datetime import datetime
from typing import Optional

from sqlalchemy import (
    Boolean,
    CHAR,
    CheckConstraint,
    ForeignKey,
    Index,
    Integer,
    LargeBinary,
    String,
    Text,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from api.models.base import Base, TimestampMixin, UUIDMixin


class Credential(UUIDMixin, TimestampMixin, Base):
    """
    Stores authentication credentials for various services.

    Supports multiple credential types including passwords, API keys, OAuth,
    SSH keys, and more. Sensitive data is stored encrypted using AES-256-GCM.

    Attributes:
        id: UUID primary key
        client_id: Reference to client this credential belongs to
        service_id: Reference to service this credential is for
        infrastructure_id: Reference to infrastructure component
        credential_type: Type of credential (password, api_key, oauth, etc.)
        service_name: Display name for the service (e.g., "Gitea Admin")
        username: Username for authentication
        password_encrypted: AES-256-GCM encrypted password
        api_key_encrypted: Encrypted API key
        client_id_oauth: OAuth client ID
        client_secret_encrypted: Encrypted OAuth client secret
        tenant_id_oauth: OAuth tenant ID
        public_key: SSH public key (not encrypted)
        token_encrypted: Encrypted bearer/access token
        connection_string_encrypted: Encrypted connection string
        integration_code: Integration code for services like Autotask
        external_url: External URL for the service
        internal_url: Internal URL for the service
        custom_port: Custom port number if applicable
        role_description: Description of access level/role
        requires_vpn: Whether VPN is required for access
        requires_2fa: Whether 2FA is required
        ssh_key_auth_enabled: Whether SSH key authentication is enabled
        access_level: Description of access level
        expires_at: When the credential expires
        last_rotated_at: When the credential was last rotated
        is_active: Whether the credential is currently active
        created_at: Creation timestamp
        updated_at: Last update timestamp
    """

    __tablename__ = "credentials"

    # Foreign keys
    client_id: Mapped[Optional[str]] = mapped_column(
        CHAR(36),
        ForeignKey("clients.id", ondelete="CASCADE"),
        nullable=True,
        doc="Reference to client",
    )
    service_id: Mapped[Optional[str]] = mapped_column(
        CHAR(36),
        ForeignKey("services.id", ondelete="CASCADE"),
        nullable=True,
        doc="Reference to service",
    )
    infrastructure_id: Mapped[Optional[str]] = mapped_column(
        CHAR(36),
        ForeignKey("infrastructure.id", ondelete="CASCADE"),
        nullable=True,
        doc="Reference to infrastructure component",
    )

    # Credential type and service info
    credential_type: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        doc="Type of credential",
    )
    service_name: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        doc="Display name for the service",
    )

    # Authentication fields
    username: Mapped[Optional[str]] = mapped_column(
        String(255),
        nullable=True,
        doc="Username for authentication",
    )
    password_encrypted: Mapped[Optional[bytes]] = mapped_column(
        LargeBinary,
        nullable=True,
        doc="AES-256-GCM encrypted password",
    )
    api_key_encrypted: Mapped[Optional[bytes]] = mapped_column(
        LargeBinary,
        nullable=True,
        doc="Encrypted API key",
    )

    # OAuth fields
    client_id_oauth: Mapped[Optional[str]] = mapped_column(
        String(255),
        nullable=True,
        doc="OAuth client ID",
    )
    client_secret_encrypted: Mapped[Optional[bytes]] = mapped_column(
        LargeBinary,
        nullable=True,
        doc="Encrypted OAuth client secret",
    )
    tenant_id_oauth: Mapped[Optional[str]] = mapped_column(
        String(255),
        nullable=True,
        doc="OAuth tenant ID",
    )

    # SSH and token fields
    public_key: Mapped[Optional[str]] = mapped_column(
        Text,
        nullable=True,
        doc="SSH public key",
    )
    token_encrypted: Mapped[Optional[bytes]] = mapped_column(
        LargeBinary,
        nullable=True,
        doc="Encrypted bearer/access token",
    )
    connection_string_encrypted: Mapped[Optional[bytes]] = mapped_column(
        LargeBinary,
        nullable=True,
        doc="Encrypted connection string",
    )
    integration_code: Mapped[Optional[str]] = mapped_column(
        String(255),
        nullable=True,
        doc="Integration code for services like Autotask",
    )

    # Metadata
    external_url: Mapped[Optional[str]] = mapped_column(
        String(500),
        nullable=True,
        doc="External URL for the service",
    )
    internal_url: Mapped[Optional[str]] = mapped_column(
        String(500),
        nullable=True,
        doc="Internal URL for the service",
    )
    custom_port: Mapped[Optional[int]] = mapped_column(
        Integer,
        nullable=True,
        doc="Custom port number",
    )
    role_description: Mapped[Optional[str]] = mapped_column(
        String(500),
        nullable=True,
        doc="Description of access level/role",
    )
    requires_vpn: Mapped[bool] = mapped_column(
        Boolean,
        nullable=False,
        server_default="0",
        doc="Whether VPN is required",
    )
    requires_2fa: Mapped[bool] = mapped_column(
        Boolean,
        nullable=False,
        server_default="0",
        doc="Whether 2FA is required",
    )
    ssh_key_auth_enabled: Mapped[bool] = mapped_column(
        Boolean,
        nullable=False,
        server_default="0",
        doc="Whether SSH key authentication is enabled",
    )
    access_level: Mapped[Optional[str]] = mapped_column(
        String(100),
        nullable=True,
        doc="Description of access level",
    )

    # Lifecycle
    expires_at: Mapped[Optional[datetime]] = mapped_column(
        nullable=True,
        doc="Expiration timestamp",
    )
    last_rotated_at: Mapped[Optional[datetime]] = mapped_column(
        nullable=True,
        doc="Last rotation timestamp",
    )
    is_active: Mapped[bool] = mapped_column(
        Boolean,
        nullable=False,
        server_default="1",
        doc="Whether the credential is active",
    )

    # Table constraints
    __table_args__ = (
        CheckConstraint(
            "credential_type IN ('password', 'api_key', 'oauth', 'ssh_key', 'shared_secret', 'jwt', 'connection_string', 'certificate')",
            name="ck_credentials_type",
        ),
        Index("idx_credentials_client", "client_id"),
        Index("idx_credentials_service", "service_id"),
        Index("idx_credentials_type", "credential_type"),
        Index("idx_credentials_active", "is_active"),
    )

    def __repr__(self) -> str:
        """String representation of the credential."""
        return f"<Credential(id={self.id}, service_name={self.service_name}, type={self.credential_type})>"
