import re

from django.core.exceptions import ValidationError
from django.db import models

from apps.core.utils import CONTENT_FORMAT_CHOICES, FORMAT_PLAIN, render_content

VIDEO_SOURCE_YOUTUBE = "youtube"
VIDEO_SOURCE_UPLOAD = "upload"

VIDEO_SOURCE_CHOICES = [
    (VIDEO_SOURCE_YOUTUBE, "YouTube / external link"),
    (VIDEO_SOURCE_UPLOAD, "Uploaded file"),
]

VIDEO_SIZE_SMALL = "sm"
VIDEO_SIZE_MEDIUM = "md"
VIDEO_SIZE_LARGE = "lg"
VIDEO_SIZE_FULL = "full"

VIDEO_SIZE_CHOICES = [
    (VIDEO_SIZE_SMALL, "Small (480px)"),
    (VIDEO_SIZE_MEDIUM, "Medium (720px)"),
    (VIDEO_SIZE_LARGE, "Large (960px)"),
    (VIDEO_SIZE_FULL, "Full width"),
]

VIDEO_ASPECT_16_9 = "16/9"
VIDEO_ASPECT_4_3 = "4/3"
VIDEO_ASPECT_1_1 = "1/1"

VIDEO_ASPECT_CHOICES = [
    (VIDEO_ASPECT_16_9, "16:9 (widescreen)"),
    (VIDEO_ASPECT_4_3, "4:3 (standard)"),
    (VIDEO_ASPECT_1_1, "1:1 (square)"),
]

VIDEO_UPLOAD_EXTENSIONS = frozenset({".mp4", ".webm", ".ogg", ".mov"})

VIDEO_ADMIN_FIELDS = (
    "video_source",
    "video_url",
    "video_file",
    "video_poster",
    "video_size",
    "video_aspect_ratio",
    "video_styled_background",
)

VIDEO_ADMIN_FIELDSET = (
    "Video",
    {
        "fields": VIDEO_ADMIN_FIELDS + ("video_preview",),
        "description": (
            "Choose YouTube link or uploaded file. Set display size and aspect ratio "
            "to control how the preview appears on the site."
        ),
    },
)

YOUTUBE_ID_PATTERNS = (
    re.compile(r"(?:youtube\.com/watch\?(?:[^&]+&)*v=|youtube\.com/embed/|youtube\.com/shorts/|youtu\.be/)([\w-]{11})"),
    re.compile(r"^([\w-]{11})$"),
)


def parse_youtube_video_id(url):
    if not url:
        return ""
    value = url.strip()
    for pattern in YOUTUBE_ID_PATTERNS:
        match = pattern.search(value)
        if match:
            return match.group(1)
    return ""


def youtube_embed_url(url):
    video_id = parse_youtube_video_id(url)
    if not video_id:
        return ""
    return f"https://www.youtube-nocookie.com/embed/{video_id}"


class VideoBlockMixin(models.Model):
    video_source = models.CharField(
        max_length=20,
        choices=VIDEO_SOURCE_CHOICES,
        default=VIDEO_SOURCE_YOUTUBE,
        blank=True,
    )
    video_url = models.CharField(
        max_length=500,
        blank=True,
        help_text="YouTube watch, embed, or youtu.be link.",
    )
    video_file = models.FileField(
        upload_to="videos/",
        blank=True,
        help_text="MP4, WebM, OGG, or MOV file.",
    )
    video_poster = models.ImageField(
        upload_to="videos/posters/",
        blank=True,
        null=True,
        help_text="Optional thumbnail shown before an uploaded video plays.",
    )
    video_size = models.CharField(
        max_length=10,
        choices=VIDEO_SIZE_CHOICES,
        default=VIDEO_SIZE_MEDIUM,
    )
    video_aspect_ratio = models.CharField(
        max_length=10,
        choices=VIDEO_ASPECT_CHOICES,
        default=VIDEO_ASPECT_16_9,
    )
    video_styled_background = models.BooleanField(
        default=False,
        help_text="Glass panel with ambient glow (similar to the Downloads section).",
    )
    description_format = models.CharField(
        max_length=20,
        choices=CONTENT_FORMAT_CHOICES,
        default=FORMAT_PLAIN,
    )

    class Meta:
        abstract = True

    @property
    def youtube_embed_url(self):
        return youtube_embed_url(self.video_url)

    @property
    def has_video(self):
        if self.video_source == VIDEO_SOURCE_UPLOAD:
            return bool(self.video_file)
        return bool(self.youtube_embed_url)

    @property
    def video_size_class(self):
        return f"video-block--{self.video_size or VIDEO_SIZE_MEDIUM}"

    @property
    def video_aspect_class(self):
        ratio = (self.video_aspect_ratio or VIDEO_ASPECT_16_9).replace("/", "-")
        return f"video-block--ratio-{ratio}"

    @property
    def rendered_description(self):
        description = getattr(self, "description", "") or ""
        return render_content(description, self.description_format)

    def clean_video_fields(self, require=False):
        if not require and not self.video_url and not self.video_file:
            return
        if self.video_source == VIDEO_SOURCE_YOUTUBE:
            if not self.video_url.strip():
                raise ValidationError({"video_url": "Enter a YouTube link."})
            if not self.youtube_embed_url:
                raise ValidationError({"video_url": "Enter a valid YouTube link."})
        elif self.video_source == VIDEO_SOURCE_UPLOAD:
            if not self.video_file:
                raise ValidationError({"video_file": "Upload a video file."})
            extension = self.video_file.name.rsplit(".", 1)[-1].lower() if self.video_file.name else ""
            if f".{extension}" not in VIDEO_UPLOAD_EXTENSIONS:
                raise ValidationError(
                    {
                        "video_file": "Unsupported format. Use MP4, WebM, OGG, or MOV.",
                    }
                )
