# Copyright (C) 2017-2025  The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information

from typing import Optional

from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from django.utils.html import format_html

from swh.model.swhids import ObjectType
from swh.web.browse.browseurls import browse_route
from swh.web.browse.snapshot_context import get_snapshot_context
from swh.web.browse.utils import (
    gen_content_link,
    gen_directory_link,
    gen_link,
    gen_person_mail_link,
    gen_release_link,
    gen_revision_link,
)
from swh.web.utils import archive, format_utc_iso_date, reverse
from swh.web.utils.exc import NotFoundExc, sentry_capture_exception
from swh.web.utils.identifiers import get_swhids_info
from swh.web.utils.typing import ReleaseMetadata, SnapshotContext, SWHObjectInfo


@browse_route(
    r"release/(?P<sha1_git>[0-9a-f]+)/",
    view_name="browse-release",
    checksum_args=["sha1_git"],
)
def release_browse(request: HttpRequest, sha1_git: str) -> HttpResponse:
    """
    Django view that produces an HTML display of a release
    identified by its id.

    The url that points to it is :http:get:`/browse/release/(sha1_git)/`.
    """
    release = archive.lookup_release(sha1_git)
    snapshot_context: Optional[SnapshotContext] = None
    origin_info = None
    snapshot_id = request.GET.get("snapshot_id")
    if not snapshot_id:
        snapshot_id = request.GET.get("snapshot")
    origin_url = request.GET.get("origin_url")
    if not origin_url:
        origin_url = request.GET.get("origin")
    timestamp = request.GET.get("timestamp")
    visit_id = int(request.GET.get("visit_id", 0))
    if origin_url:
        try:
            snapshot_context = get_snapshot_context(
                snapshot_id,
                origin_url,
                timestamp,
                visit_id or None,
                release_name=release["name"],
                visit_type=request.GET.get("visit_type"),
            )
        except NotFoundExc as e:
            raw_rel_url = reverse(
                "browse-release", url_args={"sha1_git": sha1_git}, request=request
            )
            error_message = format_html(
                "The Software Heritage archive has a release "
                "with the hash you provided but the origin "
                "mentioned in your request appears broken: {}. "
                "Please check the URL and try again.\n\n"
                "Nevertheless, you can still browse the release "
                "without origin information: {}",
                origin_url,
                raw_rel_url,
            )
            if str(e).startswith("Origin"):
                raise NotFoundExc(error_message)
            else:
                raise e
        origin_info = snapshot_context["origin_info"]
    elif snapshot_id:
        snapshot_context = get_snapshot_context(
            snapshot_id, release_name=release["name"]
        )

    if snapshot_context is not None:
        snapshot_id = snapshot_context.get("snapshot_id", None)

    release_metadata = ReleaseMetadata(
        object_type=ObjectType.RELEASE,
        object_id=sha1_git,
        release=sha1_git,
        author=release["author"]["fullname"] if release["author"] else "None",
        author_url=(
            gen_person_mail_link(release["author"]) if release["author"] else "None"
        ),
        date=format_utc_iso_date(release["date"]),
        name=release["name"],
        synthetic=release["synthetic"],
        target=release["target"],
        target_type=release["target_type"],
        snapshot=snapshot_id,
        origin_url=origin_url,
    )

    release_note_lines = []
    if release["message"]:
        release_note_lines = release["message"].split("\n")

    swh_objects = [SWHObjectInfo(object_type=ObjectType.RELEASE, object_id=sha1_git)]

    vault_cooking = None

    rev_directory = None
    target_link = None
    if release["target_type"] == ObjectType.REVISION.name.lower():
        target_link = gen_revision_link(
            release["target"],
            snapshot_context=snapshot_context,
            link_text=None,
            link_attrs=None,
        )
        try:
            revision = archive.lookup_revision(release["target"])
            rev_directory = revision["directory"]
            vault_cooking = {
                "content_context": False,
                "directory_context": True,
                "directory_swhid": f"swh:1:dir:{rev_directory}",
                "revision_context": True,
                "revision_swhid": f"swh:1:rev:{release['target']}",
            }
            swh_objects.append(
                SWHObjectInfo(
                    object_type=ObjectType.REVISION, object_id=release["target"]
                )
            )
            swh_objects.append(
                SWHObjectInfo(object_type=ObjectType.DIRECTORY, object_id=rev_directory)
            )
        except Exception as exc:
            sentry_capture_exception(exc)
    elif release["target_type"] == ObjectType.DIRECTORY.name.lower():
        target_link = gen_directory_link(
            release["target"],
            snapshot_context=snapshot_context,
            link_text=None,
            link_attrs=None,
        )
        try:
            # check directory exists
            archive.lookup_directory(release["target"])
            vault_cooking = {
                "content_context": False,
                "directory_context": True,
                "directory_swhid": f"swh:1:dir:{release['target']}",
                "revision_context": False,
                "revision_swhid": None,
            }
            swh_objects.append(
                SWHObjectInfo(
                    object_type=ObjectType.DIRECTORY, object_id=release["target"]
                )
            )
        except Exception as exc:
            sentry_capture_exception(exc)
    elif release["target_type"] == ObjectType.CONTENT.name.lower():
        target_link = gen_content_link(
            release["target"],
            snapshot_context=snapshot_context,
            link_text=None,
            link_attrs=None,
        )
        swh_objects.append(
            SWHObjectInfo(object_type=ObjectType.CONTENT, object_id=release["target"])
        )
    elif release["target_type"] == ObjectType.RELEASE.name.lower():
        target_link = gen_release_link(
            release["target"],
            snapshot_context=snapshot_context,
            link_text=None,
            link_attrs=None,
        )

    rev_directory_url = None
    if rev_directory is not None:
        if origin_info:
            rev_directory_url = reverse(
                "browse-origin-directory",
                query_params={
                    "origin_url": origin_info["url"],
                    "release": release["name"],
                    "snapshot": snapshot_id,
                },
            )
        elif snapshot_id:
            rev_directory_url = reverse(
                "browse-snapshot-directory",
                url_args={"snapshot_id": snapshot_id},
                query_params={"release": release["name"]},
            )
        else:
            rev_directory_url = reverse(
                "browse-directory", url_args={"sha1_git": rev_directory}
            )

    directory_link = None
    if rev_directory_url is not None:
        directory_link = gen_link(rev_directory_url, rev_directory)
    release["directory_link"] = directory_link
    release["target_link"] = target_link

    if snapshot_context:
        snapshot_id = snapshot_context["snapshot_id"]

    if snapshot_id:
        swh_objects.append(
            SWHObjectInfo(object_type=ObjectType.SNAPSHOT, object_id=snapshot_id)
        )

    swhids_info = get_swhids_info(swh_objects, snapshot_context)

    note_header = "None"
    if len(release_note_lines) > 0:
        note_header = release_note_lines[0]

    release["note_header"] = note_header
    release["note_body"] = "\n".join(release_note_lines[1:])

    heading = "Release - %s" % release["name"]
    if snapshot_context:
        context_found = "snapshot: %s" % snapshot_context["snapshot_id"]
        if origin_info:
            context_found = "origin: %s" % origin_info["url"]
        heading += " - %s" % context_found

    return render(
        request,
        "browse-release.html",
        {
            "heading": heading,
            "swh_object_id": swhids_info[0]["swhid"],
            "swh_object_name": "Release",
            "swh_object_metadata": release_metadata,
            "release": release,
            "snapshot_context": snapshot_context,
            "show_actions": True,
            "breadcrumbs": None,
            "vault_cooking": vault_cooking,
            "top_right_link": None,
            "swhids_info": swhids_info,
        },
    )
