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

"""
Test suite for cart/draft persistence in website_sale_aplicoop.

Coverage:
- Save draft order (empty, with items)
- Load draft order
- Draft consistency (prices don't change unexpectedly)
- Product archived in draft (handling)
- Merge inconsistent drafts
- Draft timeline (very old draft, recent draft)
"""

from datetime import datetime
from datetime import timedelta

from odoo.tests.common import TransactionCase


class TestSaveDraftOrder(TransactionCase):
    """Test saving draft orders."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
            }
        )

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

        self.group.member_ids = [(4, self.member_partner.id)]

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

        self.category = self.env["product.category"].create(
            {
                "name": "Test Category",
            }
        )

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

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

        start_date = datetime.now().date()
        self.group_order = self.env["group.order"].create(
            {
                "name": "Test Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": start_date + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "pickup_date": start_date + timedelta(days=3),
                "cutoff_day": "0",
            }
        )
        self.group_order.action_open()
        self.group_order.product_ids = [(4, self.product1.id), (4, self.product2.id)]

    def test_save_draft_with_items(self):
        """Test saving draft order with products."""
        draft_order = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product1.id,
                            "product_qty": 2,
                            "price_unit": self.product1.list_price,
                        },
                    ),
                    (
                        0,
                        0,
                        {
                            "product_id": self.product2.id,
                            "product_qty": 1,
                            "price_unit": self.product2.list_price,
                        },
                    ),
                ],
            }
        )

        self.assertTrue(draft_order.exists())
        self.assertEqual(draft_order.state, "draft")
        self.assertEqual(len(draft_order.order_line), 2)

    def test_save_draft_empty_order(self):
        """Test saving draft order without items."""
        # Edge case: empty draft
        empty_draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [],
            }
        )

        # Should be valid (user hasn't added products yet)
        self.assertTrue(empty_draft.exists())
        self.assertEqual(len(empty_draft.order_line), 0)

    def test_save_draft_updates_existing(self):
        """Test that saving draft updates existing draft, not creates new."""
        # Create initial draft
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product1.id,
                            "product_qty": 1,
                        },
                    )
                ],
            }
        )

        draft_id = draft.id

        # Simulate "save" with different quantity
        draft.order_line[0].product_qty = 5

        # Should be same draft, not new one
        updated_draft = self.env["sale.order"].browse(draft_id)
        self.assertTrue(updated_draft.exists())
        self.assertEqual(updated_draft.order_line[0].product_qty, 5)

    def test_save_draft_preserves_group_order_reference(self):
        """Test that group_order_id is preserved when saving."""
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
            }
        )

        # Link must be preserved
        self.assertEqual(draft.group_order_id, self.group_order)

    def test_save_draft_preserves_pickup_date(self):
        """Test that pickup_date is preserved in draft."""
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "pickup_date": self.group_order.pickup_date,
                "state": "draft",
            }
        )

        self.assertEqual(draft.pickup_date, self.group_order.pickup_date)


class TestLoadDraftOrder(TransactionCase):
    """Test loading (retrieving) draft orders."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
            }
        )

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

        self.group.member_ids = [(4, self.member_partner.id)]

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

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

        start_date = datetime.now().date()
        self.group_order = self.env["group.order"].create(
            {
                "name": "Test Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": start_date + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "cutoff_day": "0",
            }
        )
        self.group_order.action_open()

    def test_load_existing_draft(self):
        """Test loading an existing draft order."""
        # Create draft
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product.id,
                            "product_qty": 3,
                        },
                    )
                ],
            }
        )

        # Load it
        loaded = self.env["sale.order"].search(
            [
                ("id", "=", draft.id),
                ("partner_id", "=", self.member_partner.id),
                ("state", "=", "draft"),
            ]
        )

        self.assertEqual(len(loaded), 1)
        self.assertEqual(loaded[0].order_line[0].product_qty, 3)

    def test_load_draft_not_visible_to_other_user(self):
        """Test that draft from one user not accessible to another."""
        # Create draft for member_partner
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
            }
        )

        # Create another user/partner
        other_partner = self.env["res.partner"].create(
            {
                "name": "Other Member",
                "email": "other@test.com",
            }
        )

        self.env["res.users"].create(
            {
                "name": "Other User",
                "login": "other@test.com",
                "partner_id": other_partner.id,
            }
        )

        # Other user should not see original draft
        other_drafts = self.env["sale.order"].search(
            [
                ("id", "=", draft.id),
                ("partner_id", "=", other_partner.id),
            ]
        )

        self.assertEqual(len(other_drafts), 0)

    def test_load_draft_from_expired_order(self):
        """Test loading draft from closed/expired group order."""
        # Close the group order
        self.group_order.action_close()

        # Create draft before closure (simulated)
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
            }
        )

        # Draft should still be loadable (but should warn)
        loaded = self.env["sale.order"].browse(draft.id)
        self.assertTrue(loaded.exists())
        # Controller should check: group_order.state and warn if closed


class TestDraftConsistency(TransactionCase):
    """Test that draft prices remain consistent across saves."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
            }
        )

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

        self.group.member_ids = [(4, self.member_partner.id)]

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

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

        start_date = datetime.now().date()
        self.group_order = self.env["group.order"].create(
            {
                "name": "Test Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": start_date + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "cutoff_day": "0",
            }
        )
        self.group_order.action_open()

    def test_draft_price_snapshot(self):
        """Test that draft captures price at time of save."""
        original_price = self.product.list_price

        # Save draft with current price
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product.id,
                            "product_qty": 1,
                            "price_unit": original_price,
                        },
                    )
                ],
            }
        )

        saved_price = draft.order_line[0].price_unit

        # Change product price
        self.product.list_price = 150.0

        # Draft should still have original price
        self.assertEqual(draft.order_line[0].price_unit, saved_price)
        self.assertNotEqual(draft.order_line[0].price_unit, self.product.list_price)

    def test_draft_quantity_consistency(self):
        """Test that quantities are preserved across saves."""
        # Save draft
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product.id,
                            "product_qty": 5,
                        },
                    )
                ],
            }
        )

        # Re-load draft
        reloaded = self.env["sale.order"].browse(draft.id)
        self.assertEqual(reloaded.order_line[0].product_qty, 5)


class TestProductArchivedInDraft(TransactionCase):
    """Test handling when product in draft gets archived."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
            }
        )

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

        self.group.member_ids = [(4, self.member_partner.id)]

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

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

        start_date = datetime.now().date()
        self.group_order = self.env["group.order"].create(
            {
                "name": "Test Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": start_date + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "cutoff_day": "0",
            }
        )
        self.group_order.action_open()

    def test_load_draft_with_archived_product(self):
        """Test loading draft when product has been archived."""
        # Create draft with active product
        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": self.group_order.id,
                "state": "draft",
                "order_line": [
                    (
                        0,
                        0,
                        {
                            "product_id": self.product.id,
                            "product_qty": 2,
                        },
                    )
                ],
            }
        )

        # Archive the product
        self.product.active = False

        # Load draft - should still work (historical data)
        loaded = self.env["sale.order"].browse(draft.id)
        self.assertTrue(loaded.exists())
        # But product may not be editable/accessible


class TestDraftTimeline(TransactionCase):
    """Test very old vs recent drafts."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Test Group",
                "is_company": True,
            }
        )

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

        self.group.member_ids = [(4, self.member_partner.id)]

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

    def test_draft_from_current_week(self):
        """Test draft from current/open group order."""
        start_date = datetime.now().date()
        current_order = self.env["group.order"].create(
            {
                "name": "Current Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": start_date,
                "end_date": start_date + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "3",
                "cutoff_day": "0",
            }
        )
        current_order.action_open()

        draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": current_order.id,
                "state": "draft",
            }
        )

        # Should be accessible and valid
        self.assertTrue(draft.exists())
        self.assertEqual(draft.group_order_id.state, "open")

    def test_draft_from_old_order_6_months_ago(self):
        """Test draft from order that was 6 months ago."""
        old_start = datetime.now().date() - timedelta(days=180)
        old_end = old_start + timedelta(days=7)

        old_order = self.env["group.order"].create(
            {
                "name": "Old Order",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": old_start,
                "end_date": old_end,
                "period": "weekly",
                "pickup_day": "3",
                "cutoff_day": "0",
            }
        )
        old_order.action_open()
        old_order.action_close()

        old_draft = self.env["sale.order"].create(
            {
                "partner_id": self.member_partner.id,
                "group_order_id": old_order.id,
                "state": "draft",
            }
        )

        # Should still exist but be inaccessible (order closed)
        self.assertTrue(old_draft.exists())
        self.assertEqual(old_order.state, "closed")

    def test_draft_order_count_for_user(self):
        """Test counting total drafts for a user."""
        # Create multiple orders and drafts
        orders = []
        for i in range(3):
            start = datetime.now().date() + timedelta(days=i * 7)
            order = self.env["group.order"].create(
                {
                    "name": f"Order {i}",
                    "group_ids": [(6, 0, [self.group.id])],
                    "type": "regular",
                    "start_date": start,
                    "end_date": start + timedelta(days=7),
                    "period": "weekly",
                    "pickup_day": "3",
                    "cutoff_day": "0",
                }
            )
            order.action_open()
            orders.append(order)

        # Create draft for each
        for order in orders:
            self.env["sale.order"].create(
                {
                    "partner_id": self.member_partner.id,
                    "group_order_id": order.id,
                    "state": "draft",
                }
            )

        # Count drafts for user
        user_drafts = self.env["sale.order"].search(
            [
                ("partner_id", "=", self.member_partner.id),
                ("state", "=", "draft"),
            ]
        )

        self.assertEqual(len(user_drafts), 3)
