# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from datetime import datetime
from datetime import timedelta

from odoo.tests.common import TransactionCase


class TestEskaerShop(TransactionCase):
    """Test suite para la lógica de eskaera_shop (descubrimiento de productos)."""

    def setUp(self):
        super().setUp()

        # Crear un grupo (res.partner)
        self.group = self.env["res.partner"].create(
            {
                "name": "Grupo Test Eskaera",
                "is_company": True,
                "email": "grupo@test.com",
            }
        )

        # Crear usuario miembro del grupo
        user_partner = self.env["res.partner"].create(
            {
                "name": "Usuario Test Partner",
                "email": "usuario_test@test.com",
            }
        )

        self.user = self.env["res.users"].create(
            {
                "name": "Usuario Test",
                "login": "usuario_test@test.com",
                "email": "usuario_test@test.com",
                "partner_id": user_partner.id,
            }
        )

        # Añadir el partner del usuario como miembro del grupo
        self.group.member_ids = [(4, user_partner.id)]

        # Crear categorías de producto
        self.category1 = self.env["product.category"].create(
            {
                "name": "Categoría Test 1",
            }
        )

        self.category2 = self.env["product.category"].create(
            {
                "name": "Categoría Test 2",
            }
        )

        # Crear proveedor
        self.supplier = self.env["res.partner"].create(
            {
                "name": "Proveedor Test",
                "is_company": True,
                "supplier_rank": 1,
                "email": "proveedor@test.com",
            }
        )

        # Crear productos
        self.product_cat1 = self.env["product.product"].create(
            {
                "name": "Producto Categoría 1",
                "type": "consu",
                "list_price": 10.0,
                "categ_id": self.category1.id,
                "active": True,
            }
        )
        self.product_cat1.product_tmpl_id.write(
            {
                "is_published": True,
                "sale_ok": True,
            }
        )

        self.product_cat2 = self.env["product.product"].create(
            {
                "name": "Producto Categoría 2",
                "type": "consu",
                "list_price": 20.0,
                "categ_id": self.category2.id,
                "active": True,
            }
        )
        self.product_cat2.product_tmpl_id.write(
            {
                "is_published": True,
                "sale_ok": True,
            }
        )

        # Crear producto con relación a proveedor
        self.product_supplier_template = self.env["product.template"].create(
            {
                "name": "Producto Proveedor",
                "type": "consu",
                "list_price": 30.0,
                "categ_id": self.category1.id,
                "is_published": True,
                "sale_ok": True,
            }
        )

        self.product_supplier = self.product_supplier_template.product_variant_ids[0]
        self.product_supplier.active = True

        # Crear relación con proveedor
        self.env["product.supplierinfo"].create(
            {
                "product_tmpl_id": self.product_supplier_template.id,
                "partner_id": self.supplier.id,
                "min_qty": 1.0,
            }
        )

        self.product_direct = self.env["product.product"].create(
            {
                "name": "Producto Directo",
                "type": "consu",
                "list_price": 40.0,
                "categ_id": self.category1.id,
                "active": True,
            }
        )
        self.product_direct.product_tmpl_id.write(
            {
                "is_published": True,
                "sale_ok": True,
            }
        )

    def test_product_discovery_direct(self):
        """Test que los productos directos se descubren correctamente."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Directo",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "product_ids": [(6, 0, [self.product_direct.id])],
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop
        products = order.product_ids

        self.assertEqual(len(products), 1)
        self.assertIn(self.product_direct, products)

        products = self.env["product.product"]._get_products_for_group_order(order.id)
        self.assertIn(
            self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
        )

    def test_product_discovery_by_category(self):
        """Test que los productos se descubren por categoría cuando no hay directos."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido por Categoría",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "category_ids": [(6, 0, [self.category1.id])],
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop (fallback a categorías)
        products = order.product_ids
        if not products:
            products = self.env["product.product"].search(
                [
                    ("categ_id", "in", order.category_ids.ids),
                ]
            )

        # Debe incluir todos los productos de la categoría 1
        self.assertGreaterEqual(len(products), 2)
        self.assertIn(
            self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertIn(
            self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
        )

        order.write({"category_ids": [(4, self.category1.id)]})
        products = self.env["product.product"]._get_products_for_group_order(order.id)
        self.assertIn(
            self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertNotIn(
            self.product_cat2.product_tmpl_id, products.mapped("product_tmpl_id")
        )

    def test_product_discovery_by_supplier(self):
        """Test que los productos se descubren por proveedor cuando no hay directos ni categorías."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido por Proveedor",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "supplier_ids": [(6, 0, [self.supplier.id])],
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop (fallback a proveedores)
        products = order.product_ids
        if not products and order.category_ids:
            products = self.env["product.product"].search(
                [
                    ("categ_id", "in", order.category_ids.ids),
                ]
            )

        if not products and order.supplier_ids:
            # Buscar productos que tienen estos proveedores en seller_ids
            product_templates = self.env["product.template"].search(
                [
                    ("seller_ids.partner_id", "in", order.supplier_ids.ids),
                ]
            )
            products = product_templates.mapped("product_variant_ids")

        # Debe incluir el producto del proveedor
        self.assertEqual(len(products), 1)
        self.assertIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )

        order.write({"supplier_ids": [(4, self.supplier.id)]})
        products = self.env["product.product"]._get_products_for_group_order(order.id)
        self.assertIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )

    def test_product_discovery_priority(self):
        """Test que la prioridad de descubrimiento es: directos > categorías > proveedores."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido con Todos",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "product_ids": [(6, 0, [self.product_direct.id])],
                "category_ids": [(6, 0, [self.category1.id, self.category2.id])],
                "supplier_ids": [(6, 0, [self.supplier.id])],
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop con prioridad
        products = order.product_ids

        # Debe retornar los productos directos, no los de categoría/proveedor
        self.assertEqual(len(products), 1)
        self.assertIn(
            self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertNotIn(
            self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertNotIn(
            self.product_cat2.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertNotIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )

        # 2. The canonical helper now returns the UNION of all association
        # sources (direct products, categories, suppliers). Assert all are
        # present to reflect the new behaviour.
        products = self.env["product.product"]._get_products_for_group_order(order.id)
        tmpl_ids = products.mapped("product_tmpl_id")
        self.assertIn(self.product_direct.product_tmpl_id, tmpl_ids)
        self.assertIn(self.product_cat1.product_tmpl_id, tmpl_ids)
        self.assertIn(self.product_supplier.product_tmpl_id, tmpl_ids)

    def test_product_discovery_fallback_from_category_to_supplier(self):
        """Test que si no hay directos ni categorías, usa proveedores."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Fallback",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                # Sin product_ids
                # Sin category_ids
                "supplier_ids": [(6, 0, [self.supplier.id])],
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop
        products = order.product_ids
        if not products and order.category_ids:
            products = self.env["product.product"].search(
                [
                    ("categ_id", "in", order.category_ids.ids),
                ]
            )

        if not products and order.supplier_ids:
            # Buscar productos que tienen estos proveedores en seller_ids
            product_templates = self.env["product.template"].search(
                [
                    ("seller_ids.partner_id", "in", order.supplier_ids.ids),
                ]
            )
            products = product_templates.mapped("product_variant_ids")

        # Debe retornar productos del proveedor
        self.assertEqual(len(products), 1)
        self.assertIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )

        # Clear categories so supplier-only fallback remains active
        order.write(
            {
                "category_ids": [(5, 0, 0)],
                "supplier_ids": [(4, self.supplier.id)],
            }
        )
        products = self.env["product.product"]._get_products_for_group_order(order.id)
        self.assertIn(
            self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
        )
        self.assertNotIn(
            self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
        )

    def test_no_products_available(self):
        """Test que retorna vacío si no hay productos definidos de ninguna forma."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Sin Productos",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": (datetime.now() + timedelta(days=7)).date(),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                # Sin product_ids, category_ids, supplier_ids
            }
        )

        order.action_open()

        # Simular lo que hace eskaera_shop
        products = order.product_ids
        if not products and order.category_ids:
            products = self.env["product.product"].search(
                [
                    ("categ_id", "in", order.category_ids.ids),
                ]
            )

        if not products and order.supplier_ids:
            # Buscar productos que tienen estos proveedores en seller_ids
            product_templates = self.env["product.template"].search(
                [
                    ("seller_ids.partner_id", "in", order.supplier_ids.ids),
                ]
            )
            products = product_templates.mapped("product_variant_ids")

        # Debe estar vacío
        self.assertEqual(len(products), 0)
