from pyramid.view import view_config

from . import get_referer_or_home
from ..models.product import get_media_type
from ..lib.cache_version import compute_cache_version, apply_no_store_headers

from pyramid.httpexceptions import HTTPFound


@view_config(route_name="content", renderer="content.j2")
@view_config(route_name="content_slug", renderer="content.j2")
def content(request):
    product = request.product

    if not request.is_saas_domain and request.domain != request.shop.domain_name:
        # The content uuid in the URI matchdict is mismatched with request shop.
        request.session.flash(("Refusing to display another shop's content.", "error"))
        return HTTPFound(get_referer_or_home(request))

    if product.is_private:
        if request.user is None or request.user.can_not_edit_product(product):
            request.session.flash(("That content is private.", "error"))
            return HTTPFound(get_referer_or_home(request))

    if product.is_sellable:
        return HTTPFound(f"/p/{product.id}/{product.slug}")

    if "slug" not in request.matchdict:
        return HTTPFound(f"/c/{product.id}/{product.slug}")

    signed_get_object_url = None

    bucket_name = request.shop_bucket_name

    # Params: Bucket, IfMatch, IfModifiedSince, IfNoneMatch, IfUnmodifiedSince,
    # Key, Range, ResponseCacheControl, ResponseContentDisposition, ResponseProductEncoding,
    # ResponseContentLanguage, ResponseContentType, ResponseExpires, VersionId,
    # SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, RequestPayer, PartNumber

    params = {
        "Bucket": bucket_name,
        "Key": product.s3_key,
    }

    # The content disposition string determines whether this is:
    # * an inline image (thumbnails)
    # * an attachment (file download)
    content_disposition = product.get_content_disposition("content")

    # The content type string determines whether this is a pdf, zip, etc.
    content_type = product.get_content_type("content")

    if content_disposition:
        params["ResponseContentDisposition"] = content_disposition

    if content_type:
        params["ResponseContentType"] = content_type

    signed_get_object_url = request.shop_uploads_client.generate_presigned_url(
        ClientMethod="get_object",
        Params=params,
        # 15 minutes.
        ExpiresIn=900,
    )

    product_size = ""
    if product.has_product_file:
        product_size = product.human_product_file_bytes

    # Load comments for the content
    from ..models.comment import get_comments_for_product

    comments = get_comments_for_product(
        request.dbsession, product.id, shop=product.shop, user=request.user
    )

    related_products = []
    if product.shop.watch_mode_enabled:
        from ..models.product import get_ring_related_products, get_related_products
        ring = product.shop.discovery_ring
        if ring:
            related_products = get_ring_related_products(product, ring, forward=42)
        else:
            related_products = get_related_products(product)

    # Dynamic content page — never cache HTML at the browser. Sidebar
    # (Up Next) reflects live ring state; stale HTML produces "pocket"
    # confusion where the sidebar disagrees with reality.
    apply_no_store_headers(request.response)

    # Generate CDN URLs for karaoke tracks if available.
    # Global karaoke kill switch (MPS-22) gates all karaoke surfaces.
    instrumentals_url = None
    vocals_url = None
    karaoke_eligible = False
    extension = product.extensions.get("product")
    media_type = get_media_type(extension) if extension else None
    if request.karaoke_enabled and media_type in ("video", "audio"):
        shop = product.shop
        karaoke_eligible = bool(shop.unsandbox_public_key and shop.unsandbox_secret_key)
        cdn_base = request.shop_cdn_endpoint
        for track_name in ("instrumentals", "vocals"):
            if track_name in product.extensions:
                url = f"{cdn_base}/{product.s3_path}/{track_name}"
                if track_name == "instrumentals":
                    instrumentals_url = url
                else:
                    vocals_url = url

    return {
        "product": product,
        "product_size": product_size,
        "signed_get_object_url": signed_get_object_url,
        "comments": comments,
        "shop": product.shop,
        "related_products": related_products,
        "cache_version": compute_cache_version(product.shop),
        "instrumentals_url": instrumentals_url,
        "vocals_url": vocals_url,
        "karaoke_eligible": karaoke_eligible,
        # Only show torrent links on the public page when product is public.
        # Private/unlisted products must not spread magnet links to visitors.
        # Global torrent kill switch (MPS-22) hides all torrent surfaces too.
        "torrent_magnet_link": (
            product.torrent_magnet_link
            if request.torrent_enabled
            and product.shop.torrent_enabled
            and product.visibility == 1
            else None
        ),
        "torrent_file_url": (
            product.torrent_file_url
            if request.torrent_enabled
            and product.shop.torrent_enabled
            and product.visibility == 1
            else None
        ),
    }
