import datetime
import re

from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import formats, timezone

from bookmarks.models import BookmarkAsset, UserProfile
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin


class BookmarkDetailsModalTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
    def setUp(self):
        user = self.get_or_create_test_user()
        self.client.force_login(user)

    def get_details_form(self, soup, bookmark):
        form_url = (
            reverse("linkding:bookmarks.index.action") + f"?details={bookmark.id}"
        )
        return soup.find("form", {"action": form_url, "enctype": "multipart/form-data"})

    def get_index_details_modal(self, bookmark):
        url = reverse("linkding:bookmarks.index") + f"?details={bookmark.id}"
        response = self.client.get(url)
        soup = self.make_soup(response.content.decode())
        return soup.select_one("div.modal.bookmark-details")

    def get_shared_details_modal(self, bookmark):
        url = reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        response = self.client.get(url)
        soup = self.make_soup(response.content.decode())
        return soup.select_one("div.modal.bookmark-details")

    def has_details_modal(self, response):
        soup = self.make_soup(response.content.decode())
        return soup.select_one("div.modal.bookmark-details") is not None

    def find_section_content(self, soup, section_name):
        h3 = soup.find("h3", string=section_name)
        content = h3.find_next_sibling("div") if h3 else None
        return content

    def get_section_content(self, soup, section_name):
        content = self.find_section_content(soup, section_name)
        self.assertIsNotNone(content)
        return content

    def find_weblink(self, soup, url):
        return soup.find("a", {"class": "weblink", "href": url})

    def count_weblinks(self, soup):
        return len(soup.find_all("a", {"class": "weblink"}))

    def find_asset(self, soup, asset):
        return soup.find("div", {"data-asset-id": asset.id})

    def test_access(self):
        # own bookmark
        bookmark = self.setup_bookmark()
        response = self.client.get(
            reverse("linkding:bookmarks.index") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertTrue(self.has_details_modal(response))

        # other user's bookmark
        other_user = self.setup_user()
        bookmark = self.setup_bookmark(user=other_user)
        response = self.client.get(
            reverse("linkding:bookmarks.index") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertFalse(self.has_details_modal(response))

        # non-existent bookmark - just returns without modal in response
        response = self.client.get(
            reverse("linkding:bookmarks.index") + "?details=9999"
        )
        self.assertEqual(response.status_code, 200)
        self.assertFalse(self.has_details_modal(response))

        # guest user
        self.client.logout()
        response = self.client.get(
            reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertFalse(self.has_details_modal(response))

    def test_access_with_sharing(self):
        # shared bookmark, sharing disabled
        other_user = self.setup_user()
        bookmark = self.setup_bookmark(shared=True, user=other_user)

        response = self.client.get(
            reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertFalse(self.has_details_modal(response))

        # shared bookmark, sharing enabled
        profile = other_user.profile
        profile.enable_sharing = True
        profile.save()

        response = self.client.get(
            reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertTrue(self.has_details_modal(response))

        # shared bookmark, guest user, no public sharing
        self.client.logout()
        response = self.client.get(
            reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertFalse(self.has_details_modal(response))

        # shared bookmark, guest user, public sharing
        profile.enable_public_sharing = True
        profile.save()

        response = self.client.get(
            reverse("linkding:bookmarks.shared") + f"?details={bookmark.id}"
        )
        self.assertEqual(response.status_code, 200)
        self.assertTrue(self.has_details_modal(response))

    def test_displays_title(self):
        # with title
        bookmark = self.setup_bookmark(title="Test title")
        soup = self.get_index_details_modal(bookmark)

        title = soup.find("h2")
        self.assertIsNotNone(title)
        self.assertEqual(title.text.strip(), bookmark.title)

        # with URL only
        bookmark = self.setup_bookmark(title="")
        soup = self.get_index_details_modal(bookmark)

        title = soup.find("h2")
        self.assertIsNotNone(title)
        self.assertEqual(title.text.strip(), bookmark.url)

    def test_website_link(self):
        # basics
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.url)
        self.assertIsNotNone(link)
        self.assertEqual(link["href"], bookmark.url)
        self.assertEqual(link.text.strip(), bookmark.url)

        # favicons disabled
        bookmark = self.setup_bookmark(favicon_file="example.png")
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.url)
        image = link.select_one("img")
        self.assertIsNone(image)

        # favicons enabled, no favicon
        profile = self.get_or_create_test_user().profile
        profile.enable_favicons = True
        profile.save()

        bookmark = self.setup_bookmark(favicon_file="")
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.url)
        image = link.select_one("img")
        self.assertIsNone(image)

        # favicons enabled, favicon present
        bookmark = self.setup_bookmark(favicon_file="example.png")
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.url)
        image = link.select_one("img")
        self.assertIsNotNone(image)
        self.assertEqual(image["src"], "/static/example.png")

    def test_reader_mode_link(self):
        # no latest snapshot
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        self.assertEqual(self.count_weblinks(soup), 2)

        # snapshot is not complete
        self.setup_asset(
            bookmark,
            asset_type=BookmarkAsset.TYPE_SNAPSHOT,
            status=BookmarkAsset.STATUS_PENDING,
        )
        self.setup_asset(
            bookmark,
            asset_type=BookmarkAsset.TYPE_SNAPSHOT,
            status=BookmarkAsset.STATUS_FAILURE,
        )
        soup = self.get_index_details_modal(bookmark)
        self.assertEqual(self.count_weblinks(soup), 2)

        # not a snapshot
        self.setup_asset(
            bookmark,
            asset_type="upload",
            status=BookmarkAsset.STATUS_COMPLETE,
        )
        soup = self.get_index_details_modal(bookmark)
        self.assertEqual(self.count_weblinks(soup), 2)

        # snapshot is complete
        asset = self.setup_asset(
            bookmark,
            asset_type=BookmarkAsset.TYPE_SNAPSHOT,
            status=BookmarkAsset.STATUS_COMPLETE,
        )
        soup = self.get_index_details_modal(bookmark)
        self.assertEqual(self.count_weblinks(soup), 3)

        reader_mode_url = reverse("linkding:assets.read", args=[asset.id])
        link = self.find_weblink(soup, reader_mode_url)
        self.assertIsNotNone(link)

    def test_internet_archive_link_with_snapshot_url(self):
        bookmark = self.setup_bookmark(web_archive_snapshot_url="https://example.com/")
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        self.assertIsNotNone(link)
        self.assertEqual(link["href"], bookmark.web_archive_snapshot_url)
        self.assertEqual(link.text.strip(), "Internet Archive")

        # favicons disabled
        bookmark = self.setup_bookmark(
            web_archive_snapshot_url="https://example.com/", favicon_file="example.png"
        )
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        image = link.select_one("svg")
        self.assertIsNone(image)

        # favicons enabled, no favicon
        profile = self.get_or_create_test_user().profile
        profile.enable_favicons = True
        profile.save()

        bookmark = self.setup_bookmark(
            web_archive_snapshot_url="https://example.com/", favicon_file=""
        )
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        image = link.select_one("svg")
        self.assertIsNone(image)

        # favicons enabled, favicon present
        bookmark = self.setup_bookmark(
            web_archive_snapshot_url="https://example.com/", favicon_file="example.png"
        )
        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        image = link.select_one("svg")
        self.assertIsNotNone(image)

    def test_internet_archive_link_with_fallback_url(self):
        date_added = timezone.datetime(
            2023, 8, 11, 21, 45, 11, tzinfo=datetime.timezone.utc
        )
        bookmark = self.setup_bookmark(url="https://example.com/", added=date_added)
        fallback_web_archive_url = (
            "https://web.archive.org/web/20230811214511/https://example.com/"
        )

        soup = self.get_index_details_modal(bookmark)
        link = self.find_weblink(soup, fallback_web_archive_url)
        self.assertIsNotNone(link)
        self.assertEqual(link["href"], fallback_web_archive_url)
        self.assertEqual(link.text.strip(), "Internet Archive")

    def test_weblinks_respect_target_setting(self):
        bookmark = self.setup_bookmark(web_archive_snapshot_url="https://example.com/")

        # target blank
        profile = self.get_or_create_test_user().profile
        profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_BLANK
        profile.save()

        soup = self.get_index_details_modal(bookmark)

        website_link = self.find_weblink(soup, bookmark.url)
        self.assertIsNotNone(website_link)
        self.assertEqual(website_link["target"], UserProfile.BOOKMARK_LINK_TARGET_BLANK)

        web_archive_link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        self.assertIsNotNone(web_archive_link)
        self.assertEqual(
            web_archive_link["target"], UserProfile.BOOKMARK_LINK_TARGET_BLANK
        )

        # target self
        profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_SELF
        profile.save()

        soup = self.get_index_details_modal(bookmark)

        website_link = self.find_weblink(soup, bookmark.url)
        self.assertIsNotNone(website_link)
        self.assertEqual(website_link["target"], UserProfile.BOOKMARK_LINK_TARGET_SELF)

        web_archive_link = self.find_weblink(soup, bookmark.web_archive_snapshot_url)
        self.assertIsNotNone(web_archive_link)
        self.assertEqual(
            web_archive_link["target"], UserProfile.BOOKMARK_LINK_TARGET_SELF
        )

    def test_preview_image(self):
        # without image
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        image = soup.select_one("div.preview-image img")
        self.assertIsNone(image)

        # with image
        bookmark = self.setup_bookmark(preview_image_file="example.png")
        soup = self.get_index_details_modal(bookmark)
        image = soup.select_one("div.preview-image img")
        self.assertIsNone(image)

        # preview images enabled, no image
        profile = self.get_or_create_test_user().profile
        profile.enable_preview_images = True
        profile.save()

        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        image = soup.select_one("div.preview-image img")
        self.assertIsNone(image)

        # preview images enabled, image present
        bookmark = self.setup_bookmark(preview_image_file="example.png")
        soup = self.get_index_details_modal(bookmark)
        image = soup.select_one("div.preview-image img")
        self.assertIsNotNone(image)
        self.assertEqual(image["src"], "/static/example.png")

    def test_status(self):
        # renders form
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)

        form = self.get_details_form(soup, bookmark)
        self.assertIsNotNone(form)
        self.assertEqual(form["method"], "post")

        # sharing disabled
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Status")

        archived = section.find("input", {"type": "checkbox", "name": "is_archived"})
        self.assertIsNotNone(archived)
        unread = section.find("input", {"type": "checkbox", "name": "unread"})
        self.assertIsNotNone(unread)
        shared = section.find("input", {"type": "checkbox", "name": "shared"})
        self.assertIsNone(shared)

        # sharing enabled
        profile = self.get_or_create_test_user().profile
        profile.enable_sharing = True
        profile.save()

        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Status")

        archived = section.find("input", {"type": "checkbox", "name": "is_archived"})
        self.assertIsNotNone(archived)
        unread = section.find("input", {"type": "checkbox", "name": "unread"})
        self.assertIsNotNone(unread)
        shared = section.find("input", {"type": "checkbox", "name": "shared"})
        self.assertIsNotNone(shared)

        # unchecked
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Status")

        archived = section.find("input", {"type": "checkbox", "name": "is_archived"})
        self.assertFalse(archived.has_attr("checked"))
        unread = section.find("input", {"type": "checkbox", "name": "unread"})
        self.assertFalse(unread.has_attr("checked"))
        shared = section.find("input", {"type": "checkbox", "name": "shared"})
        self.assertFalse(shared.has_attr("checked"))

        # checked
        bookmark = self.setup_bookmark(is_archived=True, unread=True, shared=True)
        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Status")

        archived = section.find("input", {"type": "checkbox", "name": "is_archived"})
        self.assertTrue(archived.has_attr("checked"))
        unread = section.find("input", {"type": "checkbox", "name": "unread"})
        self.assertTrue(unread.has_attr("checked"))
        shared = section.find("input", {"type": "checkbox", "name": "shared"})
        self.assertTrue(shared.has_attr("checked"))

    def test_status_visibility(self):
        # own bookmark
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        section = self.find_section_content(soup, "Status")
        self.assertIsNotNone(section)

        # other user's bookmark
        other_user = self.setup_user(enable_sharing=True)
        bookmark = self.setup_bookmark(user=other_user, shared=True)
        soup = self.get_shared_details_modal(bookmark)
        section = self.find_section_content(soup, "Status")
        self.assertIsNone(section)

        # guest user
        self.client.logout()
        other_user.profile.enable_public_sharing = True
        other_user.profile.save()
        bookmark = self.setup_bookmark(user=other_user, shared=True)
        soup = self.get_shared_details_modal(bookmark)
        section = self.find_section_content(soup, "Status")
        self.assertIsNone(section)

    def test_date_added(self):
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Date added")

        expected_date = formats.date_format(bookmark.date_added, "DATETIME_FORMAT")
        date = section.find("span", string=expected_date)
        self.assertIsNotNone(date)

    def test_tags(self):
        # without tags
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)

        section = self.find_section_content(soup, "Tags")
        self.assertIsNone(section)

        # with tags
        bookmark = self.setup_bookmark(tags=[self.setup_tag(), self.setup_tag()])

        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Tags")

        for tag in bookmark.tags.all():
            tag_link = section.find("a", string=f"#{tag.name}")
            self.assertIsNotNone(tag_link)
            expected_url = reverse("linkding:bookmarks.index") + f"?q=%23{tag.name}"
            self.assertEqual(tag_link["href"], expected_url)

    def test_description(self):
        # without description
        bookmark = self.setup_bookmark(description="")
        soup = self.get_index_details_modal(bookmark)

        section = self.find_section_content(soup, "Description")
        self.assertIsNone(section)

        # with description
        bookmark = self.setup_bookmark(description="Test description")
        soup = self.get_index_details_modal(bookmark)

        section = self.get_section_content(soup, "Description")
        self.assertEqual(section.text.strip(), bookmark.description)

    def test_notes(self):
        # without notes
        bookmark = self.setup_bookmark()
        soup = self.get_index_details_modal(bookmark)

        section = self.find_section_content(soup, "Notes")
        self.assertIsNone(section)

        # with notes
        bookmark = self.setup_bookmark(notes="Test notes")
        soup = self.get_index_details_modal(bookmark)

        section = self.get_section_content(soup, "Notes")
        self.assertEqual(section.decode_contents(), "<p>Test notes</p>")

    def test_edit_link(self):
        bookmark = self.setup_bookmark()

        # with default return URL
        soup = self.get_index_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        self.assertIsNotNone(edit_link)
        expected_url = f"/bookmarks/{bookmark.id}/edit?return_url=/bookmarks%3Fdetails%3D{bookmark.id}"
        self.assertEqual(expected_url, edit_link["href"])

    def test_delete_button(self):
        bookmark = self.setup_bookmark()

        modal = self.get_index_details_modal(bookmark)
        delete_button = modal.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNotNone(delete_button)
        self.assertEqual("Delete", delete_button.text.strip())
        self.assertEqual(str(bookmark.id), delete_button["value"])

        form = delete_button.find_parent("form")
        self.assertIsNotNone(form)
        expected_url = reverse("linkding:bookmarks.index.action")
        self.assertEqual(expected_url, form["action"])

    def test_actions_visibility(self):
        # own bookmark
        bookmark = self.setup_bookmark()

        soup = self.get_index_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        delete_button = soup.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNotNone(edit_link)
        self.assertIsNotNone(delete_button)

        # with sharing
        other_user = self.setup_user(enable_sharing=True)
        bookmark = self.setup_bookmark(user=other_user, shared=True)

        soup = self.get_shared_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        delete_button = soup.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNone(edit_link)
        self.assertIsNone(delete_button)

        # with public sharing
        profile = other_user.profile
        profile.enable_public_sharing = True
        profile.save()
        bookmark = self.setup_bookmark(user=other_user, shared=True)

        soup = self.get_shared_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        delete_button = soup.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNone(edit_link)
        self.assertIsNone(delete_button)

        # guest user
        self.client.logout()
        bookmark = self.setup_bookmark(user=other_user, shared=True)

        soup = self.get_shared_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        delete_button = soup.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNone(edit_link)
        self.assertIsNone(delete_button)

    def test_asset_list_visibility(self):
        # no assets
        bookmark = self.setup_bookmark()

        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Files")
        asset_list = section.find("div", {"class": "assets"})
        self.assertIsNone(asset_list)

        # with assets
        bookmark = self.setup_bookmark()
        self.setup_asset(bookmark)

        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Files")
        asset_list = section.find("div", {"class": "assets"})
        self.assertIsNotNone(asset_list)

    def test_asset_list(self):
        bookmark = self.setup_bookmark()
        assets = [
            self.setup_asset(bookmark),
            self.setup_asset(bookmark),
            self.setup_asset(bookmark),
        ]

        soup = self.get_index_details_modal(bookmark)
        section = self.get_section_content(soup, "Files")
        asset_list = section.find("div", {"class": "assets"})

        for asset in assets:
            asset_item = self.find_asset(asset_list, asset)
            self.assertIsNotNone(asset_item)

            asset_icon = asset_item.select_one(".list-item-icon svg")
            self.assertIsNotNone(asset_icon)

            asset_text = asset_item.select_one(".list-item-text span")
            self.assertIsNotNone(asset_text)
            self.assertIn(asset.display_name, asset_text.text)

            view_url = reverse("linkding:assets.view", args=[asset.id])
            view_link = asset_item.find("a", {"href": view_url})
            self.assertIsNotNone(view_link)

    @override_settings(LD_ENABLE_SNAPSHOTS=True)
    def test_asset_list_actions_visibility(self):
        # own bookmark
        bookmark = self.setup_bookmark()

        soup = self.get_index_details_modal(bookmark)
        create_snapshot = soup.find(
            "button", {"type": "submit", "name": "create_html_snapshot"}
        )
        upload_asset = soup.find("button", {"type": "submit", "name": "upload_asset"})
        self.assertIsNotNone(create_snapshot)
        self.assertIsNotNone(upload_asset)

        # with sharing
        other_user = self.setup_user(enable_sharing=True)
        bookmark = self.setup_bookmark(user=other_user, shared=True)

        soup = self.get_shared_details_modal(bookmark)
        create_snapshot = soup.find(
            "button", {"type": "submit", "name": "create_html_snapshot"}
        )
        upload_asset = soup.find("button", {"type": "submit", "name": "upload_asset"})
        self.assertIsNone(create_snapshot)
        self.assertIsNone(upload_asset)

        # with public sharing
        profile = other_user.profile
        profile.enable_public_sharing = True
        profile.save()

        soup = self.get_shared_details_modal(bookmark)
        create_snapshot = soup.find(
            "button", {"type": "submit", "name": "create_html_snapshot"}
        )
        upload_asset = soup.find("button", {"type": "submit", "name": "upload_asset"})
        self.assertIsNone(create_snapshot)
        self.assertIsNone(upload_asset)

        # guest user
        self.client.logout()
        bookmark = self.setup_bookmark(user=other_user, shared=True)

        soup = self.get_shared_details_modal(bookmark)
        edit_link = soup.find("a", string="Edit")
        delete_button = soup.find("button", {"type": "submit", "name": "remove"})
        self.assertIsNone(edit_link)
        self.assertIsNone(delete_button)

    def test_asset_list_actions_visibility_without_snapshots_enabled(self):
        bookmark = self.setup_bookmark()

        soup = self.get_index_details_modal(bookmark)
        create_snapshot = soup.find(
            "button", {"type": "submit", "name": "create_html_snapshot"}
        )
        upload_asset = soup.find("button", {"type": "submit", "name": "upload_asset"})
        self.assertIsNone(create_snapshot)
        self.assertIsNotNone(upload_asset)

    @override_settings(LD_DISABLE_ASSET_UPLOAD=True)
    def test_asset_list_actions_visibility_with_uploads_disabled(self):
        bookmark = self.setup_bookmark()

        soup = self.get_index_details_modal(bookmark)
        create_snapshot = soup.find(
            "button", {"type": "submit", "name": "create_html_snapshot"}
        )
        upload_asset = soup.find("button", {"type": "submit", "name": "upload_asset"})
        self.assertIsNone(create_snapshot)
        self.assertIsNone(upload_asset)

    def test_asset_without_file(self):
        bookmark = self.setup_bookmark()
        asset = self.setup_asset(bookmark)
        asset.file = ""
        asset.save()

        soup = self.get_index_details_modal(bookmark)
        asset_item = self.find_asset(soup, asset)
        view_url = reverse("linkding:assets.view", args=[asset.id])
        view_link = asset_item.find("a", {"href": view_url})
        self.assertIsNone(view_link)

    def test_asset_status(self):
        bookmark = self.setup_bookmark()
        pending_asset = self.setup_asset(bookmark, status=BookmarkAsset.STATUS_PENDING)
        failed_asset = self.setup_asset(bookmark, status=BookmarkAsset.STATUS_FAILURE)

        soup = self.get_index_details_modal(bookmark)

        asset_item = self.find_asset(soup, pending_asset)
        asset_text = asset_item.select_one(".list-item-text span")
        self.assertIn("(queued)", asset_text.text)

        asset_item = self.find_asset(soup, failed_asset)
        asset_text = asset_item.select_one(".list-item-text span")
        self.assertIn("(failed)", asset_text.text)

    def test_asset_file_size(self):
        bookmark = self.setup_bookmark()
        asset1 = self.setup_asset(bookmark, file_size=None)
        asset2 = self.setup_asset(bookmark, file_size=54639)
        asset3 = self.setup_asset(bookmark, file_size=11492020)

        soup = self.get_index_details_modal(bookmark)

        asset_item = self.find_asset(soup, asset1)
        asset_text = asset_item.select_one(".list-item-text")
        self.assertEqual(asset_text.text.strip(), asset1.display_name)

        asset_item = self.find_asset(soup, asset2)
        asset_text = asset_item.select_one(".list-item-text")
        self.assertIn("53.4\xa0KB", asset_text.text)

        asset_item = self.find_asset(soup, asset3)
        asset_text = asset_item.select_one(".list-item-text")
        self.assertIn("11.0\xa0MB", asset_text.text)

    def test_asset_actions_visibility(self):
        bookmark = self.setup_bookmark()

        # with file
        asset = self.setup_asset(bookmark)
        soup = self.get_index_details_modal(bookmark)

        asset_item = self.find_asset(soup, asset)
        view_link = asset_item.find("a", string="View")
        delete_button = asset_item.find(
            "button", {"type": "submit", "name": "remove_asset"}
        )
        self.assertIsNotNone(view_link)
        self.assertIsNotNone(delete_button)

        # without file
        asset.file = ""
        asset.save()
        soup = self.get_index_details_modal(bookmark)

        asset_item = self.find_asset(soup, asset)
        view_link = asset_item.find("a", string="View")
        delete_button = asset_item.find(
            "button", {"type": "submit", "name": "remove_asset"}
        )
        self.assertIsNone(view_link)
        self.assertIsNotNone(delete_button)

        # shared bookmark
        other_user = self.setup_user(enable_sharing=True, enable_public_sharing=True)
        bookmark = self.setup_bookmark(shared=True, user=other_user)
        asset = self.setup_asset(bookmark)
        soup = self.get_index_details_modal(bookmark)

        asset_item = self.find_asset(soup, asset)
        view_link = asset_item.find("a", string="View")
        delete_button = asset_item.find(
            "button", {"type": "submit", "name": "remove_asset"}
        )
        self.assertIsNotNone(view_link)
        self.assertIsNone(delete_button)

        # shared bookmark, guest user
        self.client.logout()
        soup = self.get_shared_details_modal(bookmark)

        asset_item = self.find_asset(soup, asset)
        view_link = asset_item.find("a", string="View")
        delete_button = asset_item.find(
            "button", {"type": "submit", "name": "remove_asset"}
        )
        self.assertIsNotNone(view_link)
        self.assertIsNone(delete_button)

    @override_settings(LD_ENABLE_SNAPSHOTS=True)
    def test_create_snapshot_is_disabled_when_having_pending_asset(self):
        bookmark = self.setup_bookmark()
        asset = self.setup_asset(bookmark, status=BookmarkAsset.STATUS_COMPLETE)

        # no pending asset
        soup = self.get_index_details_modal(bookmark)
        files_section = self.find_section_content(soup, "Files")
        create_button = files_section.find(
            "button", string=re.compile("Create HTML snapshot")
        )
        self.assertFalse(create_button.has_attr("disabled"))

        # with pending asset
        asset.status = BookmarkAsset.STATUS_PENDING
        asset.save()

        soup = self.get_index_details_modal(bookmark)
        files_section = self.find_section_content(soup, "Files")
        create_button = files_section.find(
            "button", string=re.compile("Create HTML snapshot")
        )
        self.assertTrue(create_button.has_attr("disabled"))
