"""
Asset configuration schemas from assets.yaml.

These schemas define CDN configuration, image optimization settings,
cache control policies, and file upload rules.

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

Usage:
    from lightwave.schema.pydantic.sst import (
        AssetsConfigSchema,
        CDNConfigSchema,
        ImageOptimizationConfig,
        CacheControlPolicy,
    )

    # Load all asset config
    config = AssetsConfigSchema.get_from_sst()
    print(config.cdn.base_url)  # "https://cdn.lightwave-media.ltd"
    print(config.image_optimization.quality.default)  # 80

    # Get cache headers for static assets
    policy = config.cache_control.static_assets
    print(policy.to_header())  # "public, max-age=31536000, immutable"
"""

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

import yaml
from pydantic import Field

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

# =============================================================================
# CDN Configuration
# =============================================================================


class CDNPathsConfig(SSTSchema):
    """CDN path prefixes for different asset types."""

    images: str = Field("/images/", description="Image path prefix")
    static: str = Field("/static/", description="Static assets path prefix")
    media: str = Field("/media/", description="Media path prefix")
    uploads: str = Field("/uploads/", description="User uploads path prefix")
    fonts: str = Field("/fonts/", description="Fonts path prefix")
    scripts: str = Field("/js/", description="JavaScript path prefix")
    styles: str = Field("/css/", description="CSS path prefix")


class CDNConfigSchema(SSTSchema):
    """CDN configuration from assets.yaml."""

    provider: Literal["cloudfront", "cloudflare", "fastly", "custom"] = Field("cloudfront", description="CDN provider")
    base_url: str = Field(..., description="CDN base URL")
    paths: CDNPathsConfig = Field(default_factory=CDNPathsConfig, description="Asset path prefixes")
    distribution_ids: dict[str, str] = Field(default_factory=dict, description="CDN distribution IDs by environment")
    s3_bucket: str | None = Field(None, description="S3 bucket name")
    s3_region: str = Field("us-east-1", description="S3 bucket region")

    def get_url(self, path_type: str, path: str) -> str:
        """
        Generate a full CDN URL for an asset.

        Args:
            path_type: Type of asset (images, static, media, etc.)
            path: Relative path to the asset

        Returns:
            Full CDN URL
        """
        prefix = getattr(self.paths, path_type, "/")
        return f"{self.base_url}{prefix}{path.lstrip('/')}"


# =============================================================================
# Image Optimization
# =============================================================================


class ImageQualityConfig(SSTSchema):
    """Image quality settings."""

    default: int = Field(80, ge=1, le=100, description="Default quality")
    thumbnail: int = Field(70, ge=1, le=100, description="Thumbnail quality")
    hero: int = Field(85, ge=1, le=100, description="Hero image quality")
    lossless: int = Field(100, ge=100, le=100, description="Lossless quality")


class ThumbnailConfig(SSTSchema):
    """Thumbnail size configuration."""

    width: int = Field(..., ge=1, description="Width in pixels")
    height: int = Field(..., ge=1, description="Height in pixels")
    fit: Literal["cover", "contain", "fill", "inside", "outside"] = Field("cover", description="Fit mode")


class ImageProcessingConfig(SSTSchema):
    """Image processing options."""

    strip_metadata: bool = Field(True, description="Remove EXIF data")
    auto_orient: bool = Field(True, description="Fix orientation from EXIF")
    progressive: bool = Field(True, description="Progressive JPEGs")
    optimize: bool = Field(True, description="Optimize PNG/GIF")


class ImageOptimizationConfig(SSTSchema):
    """Image optimization configuration from assets.yaml."""

    formats: list[Literal["webp", "avif", "jpg", "png", "gif"]] = Field(
        default_factory=lambda: ["webp", "avif", "jpg", "png"],
        description="Supported output formats in preference order",
    )
    quality: ImageQualityConfig = Field(default_factory=ImageQualityConfig, description="Quality settings")
    max_width: int = Field(2400, ge=1, description="Maximum width in pixels")
    max_height: int = Field(2400, ge=1, description="Maximum height in pixels")
    breakpoints: list[int] = Field(
        default_factory=lambda: [320, 640, 768, 1024, 1280, 1536, 1920],
        description="Responsive breakpoints for srcset",
    )
    thumbnails: dict[str, ThumbnailConfig] = Field(default_factory=dict, description="Thumbnail configurations")
    processing: ImageProcessingConfig = Field(default_factory=ImageProcessingConfig, description="Processing options")

    def get_srcset_widths(self, max_width: int | None = None) -> list[int]:
        """
        Get breakpoint widths for srcset generation.

        Args:
            max_width: Optional maximum width to filter by

        Returns:
            List of widths to generate
        """
        limit = max_width or self.max_width
        return [w for w in self.breakpoints if w <= limit]


# =============================================================================
# Cache Control
# =============================================================================


class CacheControlPolicy(SSTSchema):
    """Cache control policy configuration."""

    max_age: int = Field(0, ge=0, description="max-age in seconds")
    immutable: bool = Field(False, description="Add immutable directive")
    public: bool = Field(False, description="Public caching allowed")
    private: bool = Field(False, description="Private caching only")
    no_cache: bool = Field(False, description="no-cache directive")
    no_store: bool = Field(False, description="no-store directive")
    must_revalidate: bool = Field(False, description="must-revalidate directive")
    stale_while_revalidate: int | None = Field(None, description="stale-while-revalidate seconds")
    description: str = Field("", description="Policy description")

    def to_header(self) -> str:
        """
        Generate Cache-Control header value.

        Returns:
            Cache-Control header string
        """
        directives: list[str] = []

        if self.public:
            directives.append("public")
        if self.private:
            directives.append("private")
        if self.no_cache:
            directives.append("no-cache")
        if self.no_store:
            directives.append("no-store")
        if self.max_age >= 0 and not self.no_store:
            directives.append(f"max-age={self.max_age}")
        if self.immutable:
            directives.append("immutable")
        if self.must_revalidate:
            directives.append("must-revalidate")
        if self.stale_while_revalidate is not None:
            directives.append(f"stale-while-revalidate={self.stale_while_revalidate}")

        return ", ".join(directives)


class CacheControlConfigSchema(SSTSchema):
    """All cache control policies from assets.yaml."""

    static_assets: CacheControlPolicy = Field(default_factory=CacheControlPolicy, description="Static asset caching")
    dynamic_content: CacheControlPolicy = Field(
        default_factory=CacheControlPolicy, description="Dynamic content caching"
    )
    images: CacheControlPolicy = Field(default_factory=CacheControlPolicy, description="Image caching")
    uploads: CacheControlPolicy = Field(default_factory=CacheControlPolicy, description="Upload caching")
    api: CacheControlPolicy = Field(default_factory=CacheControlPolicy, description="API response caching")
    fonts: CacheControlPolicy = Field(default_factory=CacheControlPolicy, description="Font caching")

    def get_policy(self, asset_type: str) -> CacheControlPolicy:
        """Get cache policy for an asset type."""
        return getattr(self, asset_type, self.dynamic_content)


# =============================================================================
# File Upload Configuration
# =============================================================================


class UploadMaxSizesConfig(SSTSchema):
    """Maximum file upload sizes by type."""

    image: int = Field(10485760, description="Max image size in bytes")
    document: int = Field(52428800, description="Max document size in bytes")
    video: int = Field(524288000, description="Max video size in bytes")
    default: int = Field(10485760, description="Default max size in bytes")


class UploadNamingConfig(SSTSchema):
    """File naming configuration."""

    strategy: Literal["uuid", "hash", "timestamp"] = Field("uuid", description="Naming strategy")
    preserve_extension: bool = Field(True, description="Keep original extension")
    lowercase: bool = Field(True, description="Lowercase filenames")


class UploadConfigSchema(SSTSchema):
    """File upload configuration from assets.yaml."""

    max_sizes: UploadMaxSizesConfig = Field(default_factory=UploadMaxSizesConfig, description="Max file sizes")
    allowed_types: dict[str, list[str]] = Field(default_factory=dict, description="Allowed MIME types by category")
    naming: UploadNamingConfig = Field(default_factory=UploadNamingConfig, description="Naming configuration")
    paths: dict[str, str] = Field(default_factory=dict, description="Storage path templates")

    def is_allowed(self, mime_type: str, category: str | None = None) -> bool:
        """
        Check if a MIME type is allowed.

        Args:
            mime_type: MIME type to check
            category: Optional category to check against

        Returns:
            True if allowed
        """
        if category:
            return mime_type in self.allowed_types.get(category, [])

        # Check all categories
        for types in self.allowed_types.values():
            if mime_type in types:
                return True
        return False

    def get_max_size(self, category: str) -> int:
        """Get maximum file size for a category."""
        return getattr(self.max_sizes, category, self.max_sizes.default)


# =============================================================================
# URL Generation Configuration
# =============================================================================


class SignedUrlConfig(SSTSchema):
    """Signed URL configuration."""

    enabled: bool = Field(True, description="Enable signed URLs")
    expiry_seconds: int = Field(3600, ge=60, description="URL expiry in seconds")
    algorithm: Literal["sha256", "sha512"] = Field("sha256", description="Hash algorithm")


class PlaceholdersConfig(SSTSchema):
    """Placeholder image paths."""

    default: str = Field("/images/placeholder.svg", description="Default placeholder")
    avatar: str = Field("/images/avatar-placeholder.svg", description="Avatar placeholder")
    thumbnail: str = Field("/images/thumb-placeholder.svg", description="Thumbnail placeholder")
    error: str = Field("/images/error-placeholder.svg", description="Error placeholder")


class URLGenerationConfig(SSTSchema):
    """URL generation configuration from assets.yaml."""

    signed_urls: SignedUrlConfig = Field(default_factory=SignedUrlConfig, description="Signed URL settings")
    transformation_format: str = Field(
        "/{type}/transform/{params}/{path}",
        description="URL format for transformations",
    )
    placeholders: PlaceholdersConfig = Field(default_factory=PlaceholdersConfig, description="Placeholder images")


# =============================================================================
# Security Configuration
# =============================================================================


class HotlinkProtectionConfig(SSTSchema):
    """Hotlink protection configuration."""

    enabled: bool = Field(True, description="Enable hotlink protection")
    allowed_domains: list[str] = Field(default_factory=list, description="Allowed referrer domains")


class ContentDispositionConfig(SSTSchema):
    """Content disposition configuration."""

    force_download: list[str] = Field(default_factory=list, description="MIME types to force download")
    inline: list[str] = Field(default_factory=list, description="MIME types to display inline")


class VirusScanConfig(SSTSchema):
    """Virus scanning configuration."""

    enabled: bool = Field(True, description="Enable virus scanning")
    scan_on_upload: bool = Field(True, description="Scan files on upload")
    quarantine_path: str = Field("quarantine/", description="Quarantine path")


class AssetSecurityConfig(SSTSchema):
    """Asset security configuration from assets.yaml."""

    hotlink_protection: HotlinkProtectionConfig = Field(
        default_factory=HotlinkProtectionConfig, description="Hotlink protection"
    )
    content_disposition: ContentDispositionConfig = Field(
        default_factory=ContentDispositionConfig, description="Content disposition rules"
    )
    virus_scan: VirusScanConfig = Field(default_factory=VirusScanConfig, description="Virus scanning")


# =============================================================================
# Root Configuration Schema
# =============================================================================


class AssetsConfigSchema(SSTSchema):
    """
    Complete asset configuration from assets.yaml.

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

    Example:
        config = AssetsConfigSchema.get_from_sst()
        print(config.cdn.base_url)  # "https://cdn.lightwave-media.ltd"
        print(config.image_optimization.quality.default)  # 80
        print(config.cache_control.static_assets.to_header())
    """

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

    cdn: CDNConfigSchema
    image_optimization: ImageOptimizationConfig
    cache_control: CacheControlConfigSchema
    upload: UploadConfigSchema
    url_generation: URLGenerationConfig
    security: AssetSecurityConfig

    @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) -> "AssetsConfigSchema":
        """
        Load asset configuration from SST YAML.

        Returns:
            AssetsConfigSchema instance with all asset config
        """
        data = cls.load_sst_data()

        # Remove _meta key before validation
        data.pop("_meta", None)

        # Parse nested configurations
        if "cdn" in data and "paths" in data["cdn"]:
            data["cdn"]["paths"] = CDNPathsConfig(**data["cdn"]["paths"])

        if "image_optimization" in data:
            img_opt = data["image_optimization"]
            if "quality" in img_opt:
                img_opt["quality"] = ImageQualityConfig(**img_opt["quality"])
            if "thumbnails" in img_opt:
                img_opt["thumbnails"] = {k: ThumbnailConfig(**v) for k, v in img_opt["thumbnails"].items()}
            if "processing" in img_opt:
                img_opt["processing"] = ImageProcessingConfig(**img_opt["processing"])

        if "cache_control" in data:
            cc = data["cache_control"]
            for key in list(cc.keys()):
                cc[key] = CacheControlPolicy(**cc[key])

        if "upload" in data:
            upload = data["upload"]
            if "max_sizes" in upload:
                upload["max_sizes"] = UploadMaxSizesConfig(**upload["max_sizes"])
            if "naming" in upload:
                upload["naming"] = UploadNamingConfig(**upload["naming"])

        if "url_generation" in data:
            url_gen = data["url_generation"]
            if "signed_urls" in url_gen:
                url_gen["signed_urls"] = SignedUrlConfig(**url_gen["signed_urls"])
            if "placeholders" in url_gen:
                url_gen["placeholders"] = PlaceholdersConfig(**url_gen["placeholders"])

        if "security" in data:
            sec = data["security"]
            if "hotlink_protection" in sec:
                sec["hotlink_protection"] = HotlinkProtectionConfig(**sec["hotlink_protection"])
            if "content_disposition" in sec:
                sec["content_disposition"] = ContentDispositionConfig(**sec["content_disposition"])
            if "virus_scan" in sec:
                sec["virus_scan"] = VirusScanConfig(**sec["virus_scan"])

        return cls(**data)
