from .models import DISTRIBUTION_INSTALLABLE, DISTRIBUTION_PACKAGE, INSTALLABLE_PLATFORM_SPECS

DEFAULT_PACKAGE_RESOURCE_BUTTON_TEXT = "PyPI"
DEFAULT_PACKAGE_SOURCE_BUTTON_TEXT = "Source"


def package_button_labels(product):
    resource = (getattr(product, "package_resource_button_text", "") or "").strip()
    source = (getattr(product, "package_source_button_text", "") or "").strip()
    return {
        "package_resource_button_text": resource or DEFAULT_PACKAGE_RESOURCE_BUTTON_TEXT,
        "package_source_button_text": source or DEFAULT_PACKAGE_SOURCE_BUTTON_TEXT,
    }


def downloads_section_link(product):
    url = (getattr(product, "downloads_section_link_url", "") or "").strip()
    text = (getattr(product, "downloads_section_link_text", "") or "").strip()
    if url and text:
        return {"url": url, "text": text}
    return None


def featured_version(qs):
    ordered = qs.order_by("order", "pk")
    cand = ordered.filter(is_featured=True).first()
    return cand if cand else ordered.first()


def version_has_public_assets(version):
    return version.has_any_install_asset() or bool((version.package_resource_url or "").strip())


def install_specs_from_versions(version_list):
    present = set()
    for ver in version_list:
        for field_name, *_ in INSTALLABLE_PLATFORM_SPECS:
            if ver.has_platform_asset(field_name):
                present.add(field_name)
    return tuple(s for s in INSTALLABLE_PLATFORM_SPECS if s[0] in present)


def build_installable_channel_block(version):
    if not version_has_public_assets(version):
        return None
    block = {
        "version": version,
        "install_cells": [],
        "is_previous": version.is_previous_channel,
    }
    if version.has_any_install_asset():
        specs = install_specs_from_versions([version])
        block["install_cells"] = version.install_urls_for_specs(specs)
    return block


def build_release_context(distribution, active_versions, product):
    context = {
        "distribution_installable": distribution == DISTRIBUTION_INSTALLABLE,
        "distribution_package": distribution == DISTRIBUTION_PACKAGE,
        "show_releases_section": False,
        "featured_version": None,
        "featured_channel": None,
        "featured_install_cells": [],
        "inline_download_channels": [],
        "show_older_versions_link": False,
        "package_versions": [],
        **package_button_labels(product),
        "downloads_section_link": downloads_section_link(product),
    }

    if distribution == DISTRIBUTION_INSTALLABLE:
        featured = featured_version(active_versions)
        if featured and not version_has_public_assets(featured):
            for cand in active_versions.exclude(pk=featured.pk).order_by("order", "pk"):
                if version_has_public_assets(cand):
                    featured = cand
                    break
        context["featured_version"] = featured
        if featured and version_has_public_assets(featured):
            featured_block = build_installable_channel_block(featured)
            if featured_block:
                context["featured_channel"] = featured_block
                context["featured_install_cells"] = featured_block["install_cells"]
                context["show_releases_section"] = True

        inline_blocks = []
        for ver in active_versions.order_by("order", "pk"):
            if featured and ver.pk == featured.pk:
                continue
            if not ver.show_on_product_page:
                continue
            block = build_installable_channel_block(ver)
            if block:
                inline_blocks.append(block)
        context["inline_download_channels"] = inline_blocks

        shown_pks = {featured.pk} if featured else set()
        shown_pks.update(block["version"].pk for block in inline_blocks)
        older_qs = active_versions.order_by("order", "pk")
        if shown_pks:
            older_qs = older_qs.exclude(pk__in=shown_pks)
        context["show_older_versions_link"] = older_qs.exists()

    elif distribution == DISTRIBUTION_PACKAGE:
        pkg_versions = list(active_versions.order_by("order", "pk"))
        context["package_versions"] = pkg_versions
        context["show_releases_section"] = len(pkg_versions) > 0

    return context


def build_archive_context(distribution, active_versions, product):
    featured = featured_version(active_versions)
    inline_pks = set(
        active_versions.filter(show_on_product_page=True).values_list("pk", flat=True)
    )
    exclude_pks = set()
    if featured:
        exclude_pks.add(featured.pk)
    exclude_pks.update(inline_pks)
    archive = list(
        active_versions.exclude(pk__in=exclude_pks).order_by("order", "pk")
        if exclude_pks
        else active_versions.order_by("order", "pk")
    )
    context = {
        "featured_version": featured,
        "archive_versions": archive,
        **package_button_labels(product),
    }

    if distribution == DISTRIBUTION_INSTALLABLE:
        specs = install_specs_from_versions(archive)
        context["archive_specs"] = specs
        archive_rows_installable = []
        for ver in archive:
            cells = []
            for field_name, label, icon in specs:
                cells.append(
                    {
                        "field": field_name,
                        "label": label,
                        "icon": icon,
                        "url": ver.resolve_asset_url(field_name),
                        "external": bool((getattr(ver, field_name) or "").strip()),
                    }
                )
            archive_rows_installable.append({"version_obj": ver, "cells": cells})
        context["archive_rows_installable"] = archive_rows_installable
        context["archive_rows_package"] = False
        context["distribution_installable"] = True
        context["distribution_package"] = False
    else:
        context["archive_specs"] = ()
        context["archive_rows_installable"] = []
        context["archive_rows_package"] = True
        context["distribution_installable"] = False
        context["distribution_package"] = True

    return context
