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

from datetime import datetime
from datetime import timedelta

from psycopg2 import IntegrityError  # noqa: F401

from odoo import fields
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase


class TestGroupOrder(TransactionCase):
    """Test suite para el modelo group.order."""

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

        # Crear productos
        self.product1 = self.env["product.product"].create(
            {
                "name": "Producto Test 1",
                "type": "consu",
                "list_price": 10.0,
            }
        )

        self.product2 = self.env["product.product"].create(
            {
                "name": "Producto Test 2",
                "type": "consu",
                "list_price": 20.0,
            }
        )

    def test_create_group_order(self):
        """Test crear un pedido de grupo."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Semanal Test",
                "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",
            }
        )

        self.assertTrue(order.exists())
        self.assertEqual(order.state, "draft")
        self.assertIn(self.group, order.group_ids)

    def test_group_order_dates_validation(self):
        """Test that start_date must be before end_date"""
        with self.assertRaises(ValidationError):
            self.env["group.order"].create(
                {
                    "name": "Pedido Invalid",
                    "start_date": fields.Date.today() + timedelta(days=7),
                    "end_date": fields.Date.today(),
                }
            )

    def test_group_order_state_transitions(self):
        """Test transiciones de estado."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido State Test",
                "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",
            }
        )

        # Draft -> Open
        order.action_open()
        self.assertEqual(order.state, "open")

        # Open -> Closed
        order.action_close()
        self.assertEqual(order.state, "closed")

    def test_group_order_action_cancel(self):
        """Test cancelar un pedido."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Cancel Test",
                "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",
            }
        )

        order.action_cancel()
        self.assertEqual(order.state, "cancelled")

    def test_get_active_orders_for_week(self):
        """Test obtener pedidos activos para la semana."""
        today = datetime.now().date()
        week_start = today - timedelta(days=today.weekday())
        week_end = week_start + timedelta(days=6)

        # Crear pedido activo esta semana
        active_order = self.env["group.order"].create(
            {
                "name": "Pedido Activo",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": week_start,
                "end_date": week_end,
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "state": "open",
            }
        )

        # Crear pedido inactivo (futuro)
        future_order = self.env["group.order"].create(
            {
                "name": "Pedido Futuro",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": week_end + timedelta(days=1),
                "end_date": week_end + timedelta(days=8),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "state": "open",
            }
        )

        active_orders = self.env["group.order"].search(
            [
                ("state", "=", "open"),
                "|",
                ("end_date", ">=", week_start),
                ("end_date", "=", False),
                ("start_date", "<=", week_end),
            ]
        )

        self.assertIn(active_order, active_orders)
        self.assertNotIn(future_order, active_orders)

    def test_permanent_group_order(self):
        """Test crear un pedido permanente (sin end_date)."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Permanente",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": datetime.now().date(),
                "end_date": False,
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
            }
        )

        self.assertTrue(order.exists())
        self.assertFalse(order.end_date)

    def test_get_active_orders_excludes_draft(self):
        """Test que get_active_orders_for_week NO incluye pedidos en draft."""
        today = datetime.now().date()

        # Crear pedido en draft (no abierto)
        draft_order = self.env["group.order"].create(
            {
                "name": "Pedido Draft",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": today,
                "end_date": today + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "state": "draft",
            }
        )

        today = datetime.now().date()
        week_start = today - timedelta(days=today.weekday())
        week_end = week_start + timedelta(days=6)
        active_orders = self.env["group.order"].search(
            [
                ("state", "=", "open"),
                "|",
                ("end_date", ">=", week_start),
                ("end_date", "=", False),
                ("start_date", "<=", week_end),
            ]
        )
        self.assertNotIn(draft_order, active_orders)

    def test_get_active_orders_excludes_closed(self):
        """Test que get_active_orders_for_week NO incluye pedidos cerrados."""
        today = datetime.now().date()

        closed_order = self.env["group.order"].create(
            {
                "name": "Pedido Cerrado",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": today,
                "end_date": today + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "state": "closed",
            }
        )

        today = datetime.now().date()
        week_start = today - timedelta(days=today.weekday())
        week_end = week_start + timedelta(days=6)
        active_orders = self.env["group.order"].search(
            [
                ("state", "=", "open"),
                "|",
                ("end_date", ">=", week_start),
                ("end_date", "=", False),
                ("start_date", "<=", week_end),
            ]
        )
        self.assertNotIn(closed_order, active_orders)

    def test_get_active_orders_excludes_cancelled(self):
        """Test que get_active_orders_for_week NO incluye pedidos cancelados."""
        today = datetime.now().date()

        cancelled_order = self.env["group.order"].create(
            {
                "name": "Pedido Cancelado",
                "group_ids": [(6, 0, [self.group.id])],
                "type": "regular",
                "start_date": today,
                "end_date": today + timedelta(days=7),
                "period": "weekly",
                "pickup_day": "5",
                "cutoff_day": "0",
                "state": "cancelled",
            }
        )

        today = datetime.now().date()
        week_start = today - timedelta(days=today.weekday())
        week_end = week_start + timedelta(days=6)
        active_orders = self.env["group.order"].search(
            [
                ("state", "=", "open"),
                "|",
                ("end_date", ">=", week_start),
                ("end_date", "=", False),
                ("start_date", "<=", week_end),
            ]
        )
        self.assertNotIn(cancelled_order, active_orders)

    def test_state_transition_draft_to_open(self):
        """Test que un pedido pasa de draft a open."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Estado Test",
                "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": "5",
                "cutoff_day": "0",
            }
        )

        self.assertEqual(order.state, "draft")
        order.action_open()
        self.assertEqual(order.state, "open")

    def test_state_transition_open_to_closed(self):
        """Test transición válida open -> closed."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Estado Test",
                "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": "5",
                "cutoff_day": "0",
            }
        )

        order.action_open()
        self.assertEqual(order.state, "open")

        order.action_close()
        self.assertEqual(order.state, "closed")

    def test_state_transition_any_to_cancelled(self):
        """Test cancelar desde cualquier estado."""
        order = self.env["group.order"].create(
            {
                "name": "Pedido Estado Test",
                "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": "5",
                "cutoff_day": "0",
            }
        )

        # Desde draft
        order.action_cancel()
        self.assertEqual(order.state, "cancelled")

        # Crear otro desde open
        order2 = self.env["group.order"].create(
            {
                "name": "Pedido Estado Test 2",
                "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": "5",
                "cutoff_day": "0",
            }
        )
        order2.action_open()
        order2.action_cancel()
        self.assertEqual(order2.state, "cancelled")
