# Part of Odoo. See LICENSE file for full copyright and licensing details.

import logging

from odoo.exceptions import ValidationError
from odoo.fields import Command
from odoo.tests import HttpCase, tagged

from odoo.addons.http_routing.tests.common import MockRequest
from odoo.addons.website.tests.common import HttpCaseWithWebsiteUser
from odoo.addons.website_sale.controllers.main import WebsiteSale

_logger = logging.getLogger(__name__)

ATTACHMENT_DATA = [
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKqf3geEAAA//8EGgIyYKYzzgAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKqvvQEEAAA//8EBQI0GMlQsAAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKKLakBBAAA//8ChwFQsvFlAwAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGJqkdoACAAA//8CfAFRzSyOUAAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGLSfxgICAAA//8CrAFkoLBhpQAAAABJRU5ErkJggg==",
]
ATTACHMENT_COUNT = 5


@tagged('post_install', '-at_install')
class TestProductPictureController(HttpCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.website = cls.env['website'].browse(1)
        cls.WebsiteSaleController = WebsiteSale()
        cls.product = cls.env['product.product'].create({
            'name': 'Storage Test Box',
            'standard_price': 70.0,
            'list_price': 79.0,
            'website_published': True,
        })

        cls.attachments = cls.env['ir.attachment'].create([
            {
                'datas': ATTACHMENT_DATA[i],
                'name': f'image0{i}.gif',
                'public': True
            }
            for i in range(ATTACHMENT_COUNT)])

    def _create_product_images(self):
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'id': attachment.id} for attachment in self.attachments],
                'image',
                self.product.id,
                self.product.product_tmpl_id.id,
            )

    def _get_product_image_data(self):
        return [
            (hasattr(image, 'video_url') and image.video_url) or image.image_1920
            for image in self.product._get_images()
        ]

    def test_bulk_image_upload(self):
        # Turns attachments to product_images
        self._create_product_images()

        # Check if the media now exists on the product :
        for i, image in enumerate(self.product.product_template_image_ids):
            # Check if all names are now in the product
            self.assertIn(image.name, self.attachments.mapped('name'))
            # Check if image datas are the same
            self.assertEqual(image.image_1920, ATTACHMENT_DATA[i])
        # Check if exactly ATTACHMENT_COUNT images were saved (no dupes/misses?)
        self.assertEqual(ATTACHMENT_COUNT, len(self.product.product_template_image_ids))

    def test_image_clear(self):
        # First create some images
        self._create_product_images()
        self.assertEqual(ATTACHMENT_COUNT, len(self.product.product_template_image_ids))

        # Remove all images
        # (Exception raised if error)
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.clear_product_images(
                self.product.id,
                self.product.product_tmpl_id.id,
            )
        # According to the product, there are no variants images.
        self.assertEqual(0, len(self.product.product_template_image_ids))

    def test_extra_images_with_new_variant(self):
        # Test that adding images for a variant that is not yet created works
        product_attribute = self.env['product.attribute'].create({
            "name": "Test attribute",
            "create_variant": "dynamic",
        })
        product_attribute_values = self.env['product.attribute.value'].create([
            {
                "name" : "Test Dynamic 1",
                "attribute_id": product_attribute.id,
                "sequence": 1,
            },
            {
                "name" : "Test Dynamic 2",
                "attribute_id": product_attribute.id,
                "sequence": 2,
            }
        ])
        product_template = self.env['product.template'].create({
            "name": "test product",
            "website_published": True,
        })
        product_template_attribute_line = self.env['product.template.attribute.line'].create({
            "attribute_id": product_attribute.id,
            "product_tmpl_id": product_template.id,
            "value_ids": product_attribute_values,
        })
        self.assertEqual(0, len(product_template.product_variant_ids))
        with MockRequest(product_template.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'id': self.attachments[0].id}],
                'image',
                False,
                product_template.id,
                [product_template_attribute_line.product_template_value_ids[0].id],
            )
        self.assertEqual(1, len(product_template.product_variant_ids))

    def test_resequence_image_first(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'first',
            )
            # Trigger the reordering of product.image records based on their sequence.
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i3, i1, i2, i4, i5, i6])
            self.assertEqual(self.product.image_1920, i3)

    def test_resequence_image_left(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'left',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i3, i2, i4, i5, i6])

    def test_resequence_image_right(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'right',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i4, i3, i5, i6])

    def test_resequence_image_last(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'last',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i4, i5, i6, i3])

    def test_resequence_image_first_to_last(self):
        """Moving an image from first to last position is an edge case in the code."""
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[0]._name, images[0].id, 'last',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i2, i3, i4, i5, i6, i1])
            self.assertEqual(self.product.image_1920, i2)

    def test_resequence_video_left(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[2].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'left',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i3, i2, i4, i5, i6])

    def test_resequence_video_first(self):
        """A video can't be resequenced to first position."""
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[2].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.resequence_product_image(
                    images[2]._name, images[2].id, 'first',
                )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i3, i4, i5, i6])

    def test_resequence_video_replace_first(self):
        """A video can't replace an image that was resequenced away from first position."""
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[1].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.resequence_product_image(
                    images[0]._name, images[0].id, 'right',
                )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i3, i4, i5, i6])


@tagged('post_install', '-at_install')
class TestWebsiteSaleEditor(HttpCaseWithWebsiteUser):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user_website_user.group_ids += cls.env.ref('sales_team.group_sale_manager')
        cls.user_website_user.group_ids += cls.env.ref('product.group_product_manager')

    def test_category_page_and_products_snippet(self):
        category = self.env['product.public.category'].create({
            'name': 'Test Category',
        })
        self.env['product.public.category'].create({
            'parent_id': category.id,
            'name': 'Test Category - Child',
        })
        self.env['product.template'].create({
            'name': 'Test Product',
            'website_published': True,
            'public_categ_ids': [
                Command.link(category.id)
            ]
        })
        self.env['product.template'].create({
            'name': 'Test Product Outside Category',
            'website_published': True,
        })
        self.start_tour(
            self.env['website'].get_client_action_url('/shop'),
            'website_sale.category_page_and_products_snippet_edition',
            login='admin',
        )
        self.start_tour(
            '/shop',
            'website_sale.category_page_and_products_snippet_use',
            login=None,
        )

    def test_website_sale_restricted_editor_ui(self):
        self.env['product.template'].create({
            'name': 'Test Product',
            'website_sequence': 0,
            'website_published': True,
        })
        self.start_tour(
            self.env['website'].get_client_action_url('/shop'),
            'website_sale.restricted_editor_ui',
            login='website_user',
        )


@tagged('post_install', '-at_install')
class TestProductVideoUpload(HttpCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.website = cls.env['website'].browse(1)
        cls.WebsiteSaleController = WebsiteSale()
        cls.product = cls.env['product.product'].create({
            'name': 'Test Video Product',
            'standard_price': 100.0,
            'list_price': 120.0,
            'website_published': True,
        })
        cls.video_data = {
            'src': 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',  # A placeholder video URL
            'name': 'Test Video',
        }

    def _upload_video(self):
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'src': self.video_data['src'], 'name': self.video_data['name']}],
                'video',
                self.product.id,
                self.product.product_tmpl_id.id,
            )

    def test_video_upload(self):
        # Upload a video to the product
        self._upload_video()

        # Retrieve the product's media data
        video_url = self.product.product_template_image_ids[0].video_url
        image_1920 = self.product.product_template_image_ids[0].image_1920

        # Check that the video URL and thumbnail are correctly saved
        self.assertEqual(video_url, self.video_data['src'])
        self.assertIsNotNone(image_1920)  # Ensure a thumbnail was generated

        # Verify that the video was added as part of the media
        self.assertEqual(len(self.product.product_template_image_ids), 1)

    def test_video_upload_invalid(self):
        # Try to upload invalid video data (e.g., empty src)
        with MockRequest(self.product.env, website=self.website):
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.add_product_media(
                    [{'src': '', 'name': 'Invalid Video'}],
                    'video',
                    self.product.id,
                    self.product.product_tmpl_id.id,
                )
