"""
Security configuration schemas from security.yaml.

These schemas define the structure for JWT, sessions, rate limits,
API keys, OAuth, password policy, CORS, and security headers.

SST File: lightwave/schema/definitions/security.yaml
Database Model: None (config-driven, not DB-backed)

Usage:
    from lightwave.schema.pydantic.sst import (
        JWTConfigSchema,
        SessionConfigSchema,
        RateLimitConfigSchema,
        SecurityConfigSchema,
    )

    # Load all security config
    config = SecurityConfigSchema.get_from_sst()
    print(config.jwt.access_token_lifetime_minutes)  # 15

    # Access via registry
    from lightwave.schema.core.registry import get_registry
    registry = get_registry()
    jwt_algo = registry.security.jwt.algorithm  # "HS256"
"""

from pathlib import Path
from typing import Any, ClassVar, Literal

import yaml
from pydantic import Field

from lightwave.schema.pydantic.core.base import SSTSchema


class PowerSyncJWTConfig(SSTSchema):
    """PowerSync-specific JWT configuration (RS256)."""

    algorithm: Literal["RS256"] = Field("RS256", description="JWT signing algorithm")
    token_lifetime_minutes: int = Field(60, description="Token lifetime in minutes")


class JWTConfigSchema(SSTSchema):
    """JWT configuration from security.yaml."""

    algorithm: Literal["HS256", "RS256"] = Field("HS256", description="JWT signing algorithm")
    issuer: str = Field("lightwave", description="JWT issuer claim")
    audience: str = Field("lightwave-api", description="JWT audience claim")
    access_token_lifetime_minutes: int = Field(15, description="Access token lifetime in minutes")
    refresh_token_lifetime_days: int = Field(7, description="Refresh token lifetime in days")
    powersync: PowerSyncJWTConfig | None = Field(None, description="PowerSync-specific JWT config")


class SessionConfigSchema(SSTSchema):
    """Session/cookie configuration from security.yaml."""

    cookie_name: str = Field("lw_session", description="Session cookie name")
    cookie_secure: bool = Field(True, description="Secure cookie flag")
    cookie_httponly: bool = Field(True, description="HttpOnly cookie flag")
    cookie_samesite: Literal["strict", "lax", "none"] = Field("lax", description="SameSite cookie attribute")
    cookie_domain: str | None = Field(None, description="Cookie domain")
    max_age_days: int = Field(30, description="Session max age in days")
    track_user_agent: bool = Field(True, description="Track user agent in session")
    track_ip_address: bool = Field(True, description="Track IP address in session")


class RateLimitSchema(SSTSchema):
    """Individual rate limit configuration."""

    requests: int = Field(..., description="Number of requests allowed")
    period: Literal["second", "minute", "hour", "day"] = Field(..., description="Time period for rate limit")
    block_duration_minutes: int | None = Field(None, description="How long to block after limit exceeded")
    description: str | None = Field(None, description="Human-readable description of this rate limit")

    def to_drf_rate(self) -> str:
        """Convert to Django REST Framework throttle rate format (e.g., '100/hour')."""
        return f"{self.requests}/{self.period}"


class RateLimitsConfigSchema(SSTSchema):
    """All rate limits from security.yaml."""

    # Authentication endpoints
    login: RateLimitSchema
    signup: RateLimitSchema
    password_reset: RateLimitSchema
    email_verification: RateLimitSchema | None = None

    # API endpoints
    api_anonymous: RateLimitSchema | None = None  # Unauthenticated requests
    api_authenticated: RateLimitSchema | None = None  # Authenticated requests
    api_burst: RateLimitSchema | None = None  # Burst protection
    api_ai: RateLimitSchema | None = None  # AI/ML endpoints
    api_sensitive: RateLimitSchema | None = None  # Sensitive operations
    api_webhooks: RateLimitSchema | None = None  # Webhook endpoints

    # Legacy fields (for backwards compatibility)
    api_default: RateLimitSchema | None = None  # Deprecated: use api_anonymous
    webhook_inbound: RateLimitSchema | None = None  # Deprecated: use api_webhooks

    def get_drf_throttle_rates(self) -> dict[str, str]:
        """
        Convert rate limits to Django REST Framework THROTTLE_RATES format.

        Returns:
            Dict mapping scope names to rate strings (e.g., {'anon': '100/hour'})
        """
        rates: dict[str, str] = {}

        # Map SST fields to DRF throttle scope names
        if self.api_anonymous:
            rates["anon"] = self.api_anonymous.to_drf_rate()
        if self.api_authenticated:
            rates["user"] = self.api_authenticated.to_drf_rate()
        if self.api_burst:
            rates["burst"] = self.api_burst.to_drf_rate()
        if self.api_ai:
            rates["ai"] = self.api_ai.to_drf_rate()
        if self.api_sensitive:
            rates["sensitive"] = self.api_sensitive.to_drf_rate()
        if self.api_webhooks:
            rates["webhooks"] = self.api_webhooks.to_drf_rate()

        return rates


class AgentAPIKeyPermissions(SSTSchema):
    """Default permissions for agent API keys."""

    can_stage: bool = Field(True, description="Can stage content for review")
    can_publish: bool = Field(False, description="Can publish approved content")
    can_create: bool = Field(True, description="Can create new pages/content")
    can_delete: bool = Field(False, description="Can delete content")


class AgentAPIKeyConfigSchema(SSTSchema):
    """Agent API key configuration."""

    prefix: str = Field("lw_agent_", description="Key prefix")
    key_length: int = Field(32, description="Random key length")
    hash_algorithm: Literal["sha256", "sha512"] = Field("sha256", description="Hash algorithm for storage")
    default_permissions: AgentAPIKeyPermissions = Field(default_factory=AgentAPIKeyPermissions)
    default_rate_limit_per_minute: int = Field(100, description="Default rate limit")
    max_rate_limit_per_minute: int = Field(1000, description="Maximum rate limit")


class UserAPIKeyConfigSchema(SSTSchema):
    """User API key (PAT) configuration."""

    prefix: str = Field("lw_pat_", description="Key prefix")
    key_length: int = Field(40, description="Random key length")
    hash_algorithm: Literal["sha256", "sha512"] = Field("sha256", description="Hash algorithm for storage")
    max_keys_per_user: int = Field(10, description="Maximum keys per user")
    default_expiry_days: int = Field(90, description="Default expiry in days")


class APIKeysConfigSchema(SSTSchema):
    """API keys configuration from security.yaml."""

    agent: AgentAPIKeyConfigSchema
    user: UserAPIKeyConfigSchema | None = None


class OAuthProviderConfig(SSTSchema):
    """OAuth provider configuration."""

    enabled: bool = Field(True, description="Whether provider is enabled")
    scopes: list[str] = Field(default_factory=list, description="OAuth scopes")


class OAuthConfigSchema(SSTSchema):
    """OAuth configuration from security.yaml."""

    providers: dict[str, OAuthProviderConfig] = Field(default_factory=dict, description="OAuth provider configurations")
    token_refresh_buffer_minutes: int = Field(5, description="Refresh tokens before expiry by this many minutes")


class PasswordPolicySchema(SSTSchema):
    """Password policy configuration from security.yaml."""

    min_length: int = Field(8, ge=6, description="Minimum password length")
    max_length: int = Field(128, le=256, description="Maximum password length")
    require_uppercase: bool = Field(True, description="Require uppercase letter")
    require_lowercase: bool = Field(True, description="Require lowercase letter")
    require_digit: bool = Field(True, description="Require digit")
    require_special: bool = Field(False, description="Require special character")
    special_characters: str = Field("!@#$%^&*()_+-=[]{}|;:,.<>?", description="Allowed special characters")
    check_pwned_passwords: bool = Field(True, description="Check against HaveIBeenPwned")
    prevent_reuse_count: int = Field(5, description="Prevent reusing last N passwords")


class CORSConfigSchema(SSTSchema):
    """CORS configuration from security.yaml."""

    allowed_origins_development: list[str] = Field(default_factory=list)
    allowed_origins_production: list[str] = Field(default_factory=list)
    allow_credentials: bool = Field(True)
    allowed_methods: list[str] = Field(default_factory=lambda: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"])
    allowed_headers: list[str] = Field(default_factory=list)
    expose_headers: list[str] = Field(default_factory=list)
    max_age_seconds: int = Field(86400)


class ContentSecurityPolicySchema(SSTSchema):
    """Content Security Policy configuration."""

    default_src: list[str] = Field(default_factory=lambda: ["'self'"])
    script_src: list[str] = Field(default_factory=list)
    style_src: list[str] = Field(default_factory=list)
    img_src: list[str] = Field(default_factory=list)
    font_src: list[str] = Field(default_factory=list)
    connect_src: list[str] = Field(default_factory=list)
    frame_ancestors: list[str] = Field(default_factory=lambda: ["'none'"])


class SecurityHeadersConfigSchema(SSTSchema):
    """Security headers configuration from security.yaml."""

    content_security_policy: ContentSecurityPolicySchema = Field(default_factory=ContentSecurityPolicySchema)
    x_content_type_options: str = Field("nosniff")
    x_frame_options: Literal["DENY", "SAMEORIGIN"] = Field("DENY")
    x_xss_protection: str = Field("1; mode=block")
    referrer_policy: str = Field("strict-origin-when-cross-origin")
    permissions_policy: dict[str, list[str]] = Field(default_factory=dict)


class SecurityConfigSchema(SSTSchema):
    """
    Complete security configuration from security.yaml.

    This is the root schema that contains all security-related configuration.

    Example:
        config = SecurityConfigSchema.get_from_sst()
        print(config.jwt.algorithm)  # "HS256"
        print(config.rate_limits.login.requests)  # 10
    """

    SST_KEY: ClassVar[str] = "security"  # Registry key in __index.yaml

    jwt: JWTConfigSchema
    sessions: SessionConfigSchema
    rate_limits: RateLimitsConfigSchema
    api_keys: APIKeysConfigSchema
    oauth: OAuthConfigSchema | None = None
    password_policy: PasswordPolicySchema | None = None
    cors: CORSConfigSchema | None = None
    security_headers: SecurityHeadersConfigSchema | None = None

    @classmethod
    def get_sst_path(cls) -> Path:
        """Get path to SST YAML file (from __index.yaml registry)."""
        from lightwave.schema.core.paths import get_sst_path

        return get_sst_path(cls.SST_KEY)

    @classmethod
    def load_sst_data(cls) -> dict[str, Any]:
        """Load SST YAML file."""
        sst_path = cls.get_sst_path()
        if not sst_path.exists():
            raise FileNotFoundError(f"SST file not found: {sst_path}")
        with open(sst_path) as f:
            return yaml.safe_load(f)

    @classmethod
    def get_from_sst(cls) -> "SecurityConfigSchema":
        """
        Load security configuration from SST YAML.

        Only loads fields defined in this schema - extra top-level keys
        like 'attack_drills' are stripped. This allows the YAML to contain
        additional sections (e.g., testing frameworks) without requiring
        all Pydantic schemas to be updated simultaneously.

        Returns:
            SecurityConfigSchema instance with all security config
        """
        data = cls.load_sst_data()

        # Get only fields defined in this schema
        known_fields = set(cls.model_fields.keys())

        # Filter to only known fields, stripping _meta, attack_drills, etc.
        filtered_data = {k: v for k, v in data.items() if k in known_fields}

        return cls(**filtered_data)
