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

from datetime import datetime
from datetime import timedelta

from odoo.exceptions import ValidationError
from odoo.tests import tagged
from odoo.tests.common import HttpCase
from odoo.tests.common import TransactionCase


class GroupOrderSlugCommon:
    """Helpers to build consumer group orders with the mandatory fields."""

    def _group_order_vals(self, name, **values):
        start_date = datetime.now().date()
        vals = {
            "name": name,
            "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",
        }
        vals.update(values)
        return vals

    def _create_group_order(self, name, **values):
        return self.env["group.order"].create(self._group_order_vals(name, **values))


class TestGroupOrderSlug(GroupOrderSlugCommon, TransactionCase):
    """URL slug generation, normalization and validation."""

    def setUp(self):
        super().setUp()
        self.group = self.env["res.partner"].create(
            {
                "name": "Slug Test Group",
                "is_company": True,
                "is_group": True,
                "email": "slug-group@test.com",
            }
        )

    def test_slug_generated_from_name(self):
        order = self._create_group_order("Escola Fructuós Gelabert")
        self.assertEqual(order.slug, "escola-fructuos-gelabert")

    def test_slug_is_unique(self):
        first = self._create_group_order("Weekly Order")
        second = self._create_group_order("Weekly Order")
        self.assertEqual(first.slug, "weekly-order")
        self.assertEqual(second.slug, "weekly-order-2")

    def test_slug_is_unique_within_a_single_create(self):
        """Records created in one batch cannot see each other in the database."""
        orders = self.env["group.order"].create(
            [self._group_order_vals("Weekly Order") for _ in range(3)]
        )
        self.assertEqual(
            orders.mapped("slug"),
            ["weekly-order", "weekly-order-2", "weekly-order-3"],
        )

    def test_generated_slug_avoids_an_explicit_one_in_the_same_create(self):
        orders = self.env["group.order"].create(
            [
                self._group_order_vals("Something Else", slug="weekly-order"),
                self._group_order_vals("Weekly Order"),
            ]
        )
        self.assertEqual(orders.mapped("slug"), ["weekly-order", "weekly-order-2"])

    def test_explicit_slug_is_normalized(self):
        order = self._create_group_order("Weekly Order", slug="Fructuós Gelabert")
        self.assertEqual(order.slug, "fructuos-gelabert")

    def test_slug_kept_when_name_changes(self):
        order = self._create_group_order("Weekly Order")
        order.name = "Renamed Order"
        self.assertEqual(order.slug, "weekly-order")

    def test_emptying_slug_regenerates_it(self):
        order = self._create_group_order("Weekly Order")
        order.write({"name": "Renamed Order", "slug": False})
        self.assertEqual(order.slug, "renamed-order")

    def test_reserved_slug_is_avoided_on_generation(self):
        order = self._create_group_order("Labels")
        self.assertEqual(order.slug, "labels-eskaera")

    def test_reserved_slug_is_rejected(self):
        with self.assertRaises(ValidationError):
            self._create_group_order("Weekly Order", slug="save-order")

    def test_numeric_slug_is_rejected(self):
        with self.assertRaises(ValidationError):
            self._create_group_order("Weekly Order", slug="42")

    def test_name_without_slug_characters_falls_back(self):
        order = self._create_group_order("!!!")
        self.assertEqual(order.slug, "eskaera")


@tagged("post_install", "-at_install")
class TestGroupOrderSlugRoutes(GroupOrderSlugCommon, HttpCase):
    """The shop pages answer on the slug URL, the numeric one redirects."""

    def setUp(self):
        super().setUp()
        # is_group matters: both `res.partner.group_ids` and
        # `group.order.group_ids` filter on it when they are read.
        self.group = self.env["res.partner"].create(
            {
                "name": "Slug Routes Group",
                "is_company": True,
                "is_group": True,
                "email": "slug-routes-group@test.com",
            }
        )
        member = self.env["res.partner"].create(
            {"name": "Slug Routes Member", "email": "slug-routes-member@test.com"}
        )
        self.group.member_ids = [(4, member.id)]

        login = "portal.slug.routes@test.com"
        self.env["res.users"].create(
            {
                "name": "Slug Routes User",
                "login": login,
                "password": login,
                "partner_id": member.id,
                "groups_id": [(4, self.env.ref("base.group_portal").id)],
            }
        )
        self.portal_login = login

        self.group_order = self._create_group_order("Slug Routes Order")
        self.group_order.action_open()

        # The HTTP requests below share this transaction but not the ORM cache:
        # the many2many rows (group members, order groups) have to be in the
        # database before the controller reads them.
        self.env.flush_all()

    def test_slug_urls_answer(self):
        self.authenticate(self.portal_login, self.portal_login)
        for url in (
            f"/eskaera/{self.group_order.slug}",
            f"/eskaera/{self.group_order.slug}/checkout",
        ):
            response = self.url_open(url, allow_redirects=False)
            self.assertEqual(response.status_code, 200, url)

    def test_numeric_urls_redirect_to_slug(self):
        self.authenticate(self.portal_login, self.portal_login)
        for url, expected in (
            (f"/eskaera/{self.group_order.id}", f"/eskaera/{self.group_order.slug}"),
            (
                f"/eskaera/{self.group_order.id}/checkout",
                f"/eskaera/{self.group_order.slug}/checkout",
            ),
        ):
            response = self.url_open(url, allow_redirects=False)
            self.assertIn(response.status_code, (301, 302, 303), url)
            self.assertTrue(
                response.headers.get("Location", "").endswith(expected),
                f"{url} should redirect to {expected}, "
                f"got {response.headers.get('Location')}",
            )

    def test_numeric_url_keeps_query_parameters(self):
        """A `suffix` parameter must stay in the query string, not in the path."""
        self.authenticate(self.portal_login, self.portal_login)
        response = self.url_open(
            f"/eskaera/{self.group_order.id}/checkout?suffix=x&search=apple",
            allow_redirects=False,
        )
        self.assertIn(response.status_code, (301, 302, 303))
        location = response.headers.get("Location", "")
        self.assertIn(f"/eskaera/{self.group_order.slug}/checkout?", location)
        self.assertIn("suffix=x", location)
        self.assertIn("search=apple", location)

    def test_unknown_slug_falls_back_to_the_list(self):
        self.authenticate(self.portal_login, self.portal_login)
        response = self.url_open("/eskaera/does-not-exist", allow_redirects=False)
        self.assertIn(response.status_code, (301, 302, 303))
        self.assertTrue(response.headers.get("Location", "").endswith("/eskaera"))
