"""
Public views for media delivery.
- serve_key: returns AES-128 decryption key if the request holds a valid token
- serve_hls: proxies HLS manifest/segments via Nginx X-Accel-Redirect
- media_watch: public player page
- media_browse: browseable library
- collection_view: collection/series page
- player_embed: iframe-embeddable player
"""
from pathlib import Path

from django.conf import settings
from django.http import HttpResponse, Http404, FileResponse
from django.shortcuts import get_object_or_404, render, redirect
from django.views.decorators.cache import never_cache
from django.views.decorators.clickjacking import xframe_options_exempt

from .models import MediaItem, MediaCollection, MediaEncryptionKey


@never_cache
def serve_key(request, item_pk):
    """
    Serve the AES-128 decryption key for an HLS stream.
    Access is gated by a per-item token embedded in the m3u8.
    """
    token = request.GET.get('token', '')
    item  = get_object_or_404(MediaItem, pk=item_pk, is_active=True)
    enc   = get_object_or_404(MediaEncryptionKey, item=item, token=token)

    # Access control
    if item.access in ('premium', 'subscription'):
        if not request.user.is_authenticated:
            return HttpResponse(status=403)
        # TODO: verify active subscription when subscription model is added

    key_bytes = bytes.fromhex(enc.key_hex)
    response = HttpResponse(key_bytes, content_type='application/octet-stream')
    response['Access-Control-Allow-Origin'] = '*'
    return response


@never_cache
def serve_hls(request, item_pk, segment):
    """
    Serve HLS manifest (.m3u8) or segment (.ts) file.
    Uses Nginx X-Accel-Redirect in production; falls back to FileResponse in DEBUG.
    """
    # Validate item exists and user has access
    item = get_object_or_404(MediaItem, pk=item_pk, is_active=True, hls_status='ready')

    if item.access in ('premium', 'subscription'):
        if not request.user.is_authenticated:
            return HttpResponse(status=403)

    # Sanitise path — no directory traversal
    if '..' in segment or segment.startswith('/'):
        raise Http404

    from .utils import _hls_root
    hls_root  = _hls_root()
    file_path = hls_root / item.media_type / str(item_pk) / segment
    if not file_path.exists():
        raise Http404

    content_type = 'application/vnd.apple.mpegurl' if segment.endswith('.m3u8') else 'video/MP2T'
    response = FileResponse(open(file_path, 'rb'), content_type=content_type)
    response['Access-Control-Allow-Origin'] = '*'
    return response


# ── Public player pages ───────────────────────────────────────────────────────

def _check_access(request, item):
    """Return (allowed, redirect_url). redirect_url is set if login is needed."""
    if item.access == 'free':
        return True, None
    if not request.user.is_authenticated:
        return False, f'/auth/login/?next={request.path}'
    # premium / subscription — add subscription check here later
    return True, None


def media_watch(request, slug):
    """Full-page player for a single media item."""
    item = get_object_or_404(MediaItem, slug=slug, is_active=True, hls_status='ready')
    allowed, redir = _check_access(request, item)
    if not allowed:
        return redirect(redir)

    # External items (YouTube, SoundCloud) play in an iframe, not from our HLS
    from .embeds import embed_url as _embed_url
    external_embed = _embed_url(item.source_url)

    # HLS manifest URL (served via Django stream/ endpoint)
    hls_url = request.build_absolute_uri(f'/stream/hls/{item.pk}/index.m3u8')

    # Related items (same collection, excluding this one)
    related = []
    if item.collection:
        related = (
            MediaItem.objects
            .filter(collection=item.collection, is_active=True, hls_status='ready')
            .exclude(pk=item.pk)
            .order_by('episode_number', 'track_number', 'sort_order')[:20]
        )

    return render(request, 'media/watch.html', {
        'item':           item,
        'hls_url':        hls_url,
        'external_embed': external_embed,
        'related':        related,
    })


def media_browse(request):
    """Public media library — shows free + premium items by category."""
    qs = MediaItem.objects.filter(is_active=True, hls_status='ready').select_related('collection', 'season')

    media_type = request.GET.get('type', '')
    if media_type:
        qs = qs.filter(media_type=media_type)

    return render(request, 'media/browse.html', {
        'items':       qs.order_by('-created_at')[:60],
        'filter_type': media_type,
    })


def collection_view(request, slug):
    """Public collection/series page with episode/track list."""
    col     = get_object_or_404(MediaCollection, slug=slug, is_active=True)
    seasons = col.seasons.filter(is_active=True).prefetch_related('items') if col.has_seasons else []
    items   = (
        col.items.filter(is_active=True, hls_status='ready')
        .order_by('season__season_number', 'episode_number', 'track_number', 'sort_order')
        if not col.has_seasons else []
    )
    return render(request, 'media/collection.html', {
        'col':     col,
        'seasons': seasons,
        'items':   items,
    })


@xframe_options_exempt
@never_cache
def player_embed(request, item_pk):
    """Minimal iframe-embeddable player — no site chrome."""
    item = get_object_or_404(MediaItem, pk=item_pk, is_active=True, hls_status='ready')
    allowed, redir = _check_access(request, item)
    if not allowed:
        return HttpResponse('<p style="font-family:sans-serif;padding:1rem">Login required.</p>', status=403)

    from .embeds import embed_url as _embed_url
    hls_url = request.build_absolute_uri(f'/stream/hls/{item.pk}/index.m3u8')
    return render(request, 'media/embed.html', {
        'item':           item,
        'hls_url':        hls_url,
        'external_embed': _embed_url(item.source_url, autoplay=False),
    })


@xframe_options_exempt
def collection_embed(request, pk):
    """
    Embeddable gallery for a whole collection.

    ?layout=slider  one image at a time with arrows and a thumbnail strip (default)
    ?layout=grid    every image as a responsive grid
    ?autoplay=1     slider advances on its own
    """
    collection = get_object_or_404(MediaCollection, pk=pk, is_active=True)

    if collection.access != 'free' and not request.user.is_authenticated:
        return HttpResponse(
            '<p style="font-family:sans-serif;padding:1rem">Login required.</p>',
            status=403,
        )

    items = (
        MediaItem.objects
        .filter(collection=collection, is_active=True)
        .order_by('sort_order', 'episode_number', 'track_number', 'pk')
    )

    slides = []
    if collection.thumbnail and collection.thumbnail.name:
        slides.append({'url': collection.thumbnail.url, 'title': collection.title})
    for item in items:
        url = ''
        if item.media_type == 'image' and item.original_file:
            url = item.original_file.url
        elif item.thumbnail and item.thumbnail.name:
            url = item.thumbnail.url
        if url and url not in [s['url'] for s in slides]:
            slides.append({'url': url, 'title': item.title})

    # The collection's saved choice, overridable per embed with ?layout=
    layout = request.GET.get('layout') or collection.gallery_layout or 'slider'
    if layout not in ('slider', 'grid', 'masonry'):
        layout = 'slider'

    return render(request, 'media/collection_embed.html', {
        'collection': collection,
        'slides':     slides,
        'layout':     layout,
        'autoplay':   request.GET.get('autoplay') in ('1', 'true', 'yes'),
    })
