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

"""
Test suite for save_eskaera_draft() and save_cart_draft() endpoints.

These tests ensure that both endpoints correctly save group_order_id and
related fields (pickup_day, pickup_date, home_delivery) when creating
draft sale orders.

See: website_sale_aplicoop/controllers/website_sale.py
"""

from datetime import datetime
from datetime import timedelta

from odoo.tests.common import TransactionCase

from ..controllers.website_sale import AplicoopWebsiteSale


class TestSaveOrderEndpoints(TransactionCase):
    """Test suite for order-saving endpoints."""

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

        # Create a consumer group
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
                "is_group": True,
                "email": "group@test.com",
            }
        )

        # Create a group member (user partner)
        self.member_partner = self.env["res.partner"].create(
            {
                "name": "Group Member Partner",
                "email": "member@test.com",
            }
        )

        # Add member to group
        self.group.member_ids = [(4, self.member_partner.id)]
        if "group_ids" in self.member_partner._fields:
            self.member_partner.group_ids = [(4, self.group.id)]

        # Create test user
        self.user = self.env["res.users"].create(
            {
                "name": "Test User",
                "login": "testuser@test.com",
                "email": "testuser@test.com",
                "partner_id": self.member_partner.id,
            }
        )

        # Create a group order
        start_date = datetime.now().date()
        end_date = start_date + timedelta(days=7)

        self.group_order = self.env["group.order"].create(
            {
                "name": "Test Group Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": end_date,
                "period": "weekly",
                "pickup_day": "3",  # Wednesday
                "pickup_date": start_date + timedelta(days=3),
                "home_delivery": False,
                "cutoff_day": "0",
            }
        )

        # Open the group order
        self.group_order.action_open()

        # Create products for the order
        self.category = self.env["product.category"].create(
            {
                "name": "Test Category",
            }
        )

        self.product = self.env["product.product"].create(
            {
                "name": "Test Product",
                "type": "consu",
                "list_price": 10.0,
                "categ_id": self.category.id,
            }
        )

        # Delivery service product (required to enable home_delivery on group.order)
        self.delivery_product = self.env["product.product"].create(
            {
                "name": "Home Delivery Service",
                "type": "service",
                "list_price": 3.0,
            }
        )

        # Associate product with group order
        self.group_order.product_ids = [(4, self.product.id)]

        # Helper: controller instance for pure helpers
        self.controller = AplicoopWebsiteSale()

    def _build_line(self, product, qty, price):
        return (
            0,
            0,
            {"product_id": product.id, "product_uom_qty": qty, "price_unit": price},
        )

    def test_merge_or_replace_replaces_existing_draft(self):
        """Existing draft must be replaced (not merged) with new lines."""

        # Existing draft with one line
        existing = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "pickup_day": self.group_order.pickup_day,
                "pickup_date": self.group_order.pickup_date,
                "home_delivery": self.group_order.home_delivery,
                "order_line": [self._build_line(self.product, 1, 10.0)],
                "state": "draft",
            }
        )

        new_lines = [self._build_line(self.product, 3, 99.0)]

        result = self.controller._merge_or_replace_draft(
            self.group_order,
            self.user,
            new_lines,
            existing,
            self.group_order.id,
        )

        self.assertEqual(result.id, existing.id, "Should reuse existing draft")
        self.assertEqual(len(result.order_line), 1, "Only one line should remain")
        self.assertEqual(
            result.order_line[0].product_uom_qty, 3, "Quantity must be replaced"
        )
        self.assertEqual(
            result.order_line[0].price_unit, 99.0, "Price must be replaced"
        )

    def test_save_eskaera_draft_creates_order_with_group_order_id(self):
        """
        Test that save_eskaera_draft() creates a sale.order with group_order_id.

        This is the main fix: ensure that the /eskaera/save-order endpoint
        correctly links the created sale.order to the group.order.
        """
        # Simulate what the controller does: create order with group_order_id
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify the order was created with group_order_id
        self.assertIsNotNone(sale_order.id)
        self.assertEqual(sale_order.group_order_id.id, self.group_order.id)
        self.assertEqual(sale_order.group_order_id.name, self.group_order.name)

    def test_save_eskaera_draft_propagates_pickup_day(self):
        """Test that save_eskaera_draft() propagates pickup_day correctly."""
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify pickup_day was propagated
        self.assertEqual(sale_order.pickup_day, "3")
        self.assertEqual(sale_order.pickup_day, self.group_order.pickup_day)

    def test_save_eskaera_draft_propagates_pickup_date(self):
        """Test that save_eskaera_draft() propagates pickup_date correctly."""
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify pickup_date was propagated
        self.assertEqual(sale_order.pickup_date, self.group_order.pickup_date)

    def test_save_eskaera_draft_propagates_home_delivery(self):
        """Test that save_eskaera_draft() propagates home_delivery correctly."""
        # Create a group order with home delivery enabled via delivery_product_id
        # (home_delivery is a computed field derived from delivery_product_id)
        group_order_home = self.env["group.order"].create(
            {
                "name": "Test Group Order with Home Delivery",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": datetime.now().date() + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "pickup_date": datetime.now().date() + timedelta(days=3),
                "delivery_product_id": self.delivery_product.id,
                "cutoff_day": "0",
            }
        )

        group_order_home.action_open()

        # Test with home_delivery=True
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": group_order_home.id,
            "pickup_day": group_order_home.pickup_day,
            "pickup_date": group_order_home.pickup_date,
            "home_delivery": group_order_home.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify home_delivery was propagated
        self.assertTrue(sale_order.home_delivery)
        self.assertEqual(sale_order.home_delivery, group_order_home.home_delivery)

    def test_save_eskaera_draft_order_is_draft_state(self):
        """Test that save_eskaera_draft() creates order in draft state."""
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify order is in draft state
        self.assertEqual(sale_order.state, "draft")

    def test_save_eskaera_draft_multiple_fields_together(self):
        """
        Test that all fields are saved together correctly.

        This test ensures that the fix didn't break any field and that
        all group_order-related fields are propagated together.
        """
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify all fields together
        self.assertEqual(sale_order.group_order_id.id, self.group_order.id)
        self.assertEqual(sale_order.pickup_day, self.group_order.pickup_day)
        self.assertEqual(sale_order.pickup_date, self.group_order.pickup_date)
        self.assertEqual(sale_order.home_delivery, self.group_order.home_delivery)
        self.assertEqual(sale_order.state, "draft")

    def test_save_cart_draft_also_saves_group_order_id(self):
        """
        Test that save_cart_draft() (the working endpoint) also saves group_order_id.

        This is a regression test to ensure that save_cart_draft() continues
        to work correctly after the fix to save_eskaera_draft().
        """
        # save_cart_draft should also include group_order_id
        order_vals = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "pickup_date": self.group_order.pickup_date,
            "home_delivery": self.group_order.home_delivery,
            "order_line": [],
            "state": "draft",
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify all fields
        self.assertEqual(sale_order.group_order_id.id, self.group_order.id)
        self.assertEqual(sale_order.pickup_day, self.group_order.pickup_day)
        self.assertEqual(sale_order.pickup_date, self.group_order.pickup_date)

    def test_save_draft_order_without_group_order_id_still_works(self):
        """
        Test that creating a normal sale.order (without group_order_id) still works.

        This ensures backward compatibility - you should still be able to create
        sale orders without associating them to a group order.
        """
        order_vals = {
            "partner_id": self.member_partner.id,
            "order_line": [],
            "state": "draft",
            # No group_order_id
        }

        sale_order = self.env["sale.order"].create(order_vals)

        # Verify order was created without group_order_id
        self.assertIsNotNone(sale_order.id)
        self.assertFalse(sale_order.group_order_id)

    def test_group_order_id_field_exists_and_is_stored(self):
        """
        Test that group_order_id field exists on sale.order and is stored correctly.

        This is a sanity check to ensure the field is properly defined in the model.
        """
        # Verify the field exists in the model
        sale_order_model = self.env["sale.order"]
        self.assertIn("group_order_id", sale_order_model._fields)

        # Verify it's a Many2one field
        field = sale_order_model._fields["group_order_id"]
        self.assertEqual(field.type, "many2one")
        self.assertEqual(field.comodel_name, "group.order")

    def test_different_group_orders_map_to_different_sale_orders(self):
        """
        Test that different group orders create separate sale orders.

        This ensures that two users buying from different group orders
        don't accidentally share the same sale.order.
        """
        # Create a second group order
        group_order_2 = self.env["group.order"].create(
            {
                "name": "Test Group Order 2",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date() + timedelta(days=10),
                "end_date": datetime.now().date() + timedelta(days=17),
                "period": "weekly",
                "pickup_day": "5",
                "pickup_date": datetime.now().date() + timedelta(days=12),
                "delivery_product_id": self.delivery_product.id,
                "cutoff_day": "0",
            }
        )

        group_order_2.action_open()

        # Create order for first group order
        order_vals_1 = {
            "partner_id": self.member_partner.id,
            "group_order_id": self.group_order.id,
            "pickup_day": self.group_order.pickup_day,
            "order_line": [],
            "state": "draft",
        }

        sale_order_1 = self.env["sale.order"].create(order_vals_1)

        # Create order for second group order
        order_vals_2 = {
            "partner_id": self.member_partner.id,
            "group_order_id": group_order_2.id,
            "pickup_day": group_order_2.pickup_day,
            "order_line": [],
            "state": "draft",
        }

        sale_order_2 = self.env["sale.order"].create(order_vals_2)

        # Verify they're different orders with different group_order_ids
        self.assertNotEqual(sale_order_1.id, sale_order_2.id)
        self.assertEqual(sale_order_1.group_order_id.id, self.group_order.id)
        self.assertEqual(sale_order_2.group_order_id.id, group_order_2.id)
        self.assertNotEqual(
            sale_order_1.group_order_id.id,
            sale_order_2.group_order_id.id,
        )
