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

import json

from odoo import http
from odoo.tests import tagged
from odoo.tests.common import HttpCase

REDIRECT_URL_PARAM = "website_sale_disable_cart.redirect_url"


@tagged("post_install", "-at_install")
class TestDisableCart(HttpCase):
    """Check the standard cart endpoints are neutralized."""

    def _set_redirect_url(self, url):
        self.env["ir.config_parameter"].sudo().set_param(REDIRECT_URL_PARAM, url)

    def _location_of(self, path):
        """Return the redirect target of a GET on ``path``."""
        response = self.url_open(path, allow_redirects=False)
        self.assertIn(response.status_code, (301, 302, 303, 307, 308))
        return response.headers.get("Location", "")

    def test_cart_redirects_to_default_url(self):
        """Without configuration, /shop/cart falls back to /shop."""
        self.env["ir.config_parameter"].sudo().search(
            [("key", "=", REDIRECT_URL_PARAM)]
        ).unlink()
        self.assertTrue(self._location_of("/shop/cart").endswith("/shop"))

    def test_cart_redirects_to_configured_url(self):
        """The configured internal path is honored."""
        self._set_redirect_url("/eskaera")
        self.assertTrue(self._location_of("/shop/cart").endswith("/eskaera"))

    def test_external_redirect_url_is_rejected(self):
        """An external URL must not be used (no open redirect)."""
        self._set_redirect_url("https://example.com/phishing")
        self.assertTrue(self._location_of("/shop/cart").endswith("/shop"))

    def test_protocol_relative_redirect_url_is_rejected(self):
        """A protocol relative URL is external too."""
        self._set_redirect_url("//example.com/phishing")
        self.assertTrue(self._location_of("/shop/cart").endswith("/shop"))

    def test_cart_redirect_url_cannot_loop(self):
        """Pointing the redirect back to the cart must not loop."""
        self._set_redirect_url("/shop/cart")
        self.assertTrue(self._location_of("/shop/cart").endswith("/shop"))

    def _json_rpc(self, path, params=None):
        """Call a JSON route and return its result."""
        response = self.url_open(
            path,
            data=json.dumps(
                {"jsonrpc": "2.0", "method": "call", "params": params or {}}
            ),
            headers={"Content-Type": "application/json"},
        )
        payload = response.json()
        self.assertNotIn("error", payload, payload.get("error"))
        return payload["result"]

    def test_cart_update_redirects_without_creating_an_order(self):
        """POSTing to /shop/cart/update redirects and leaves no order behind."""
        self._set_redirect_url("/shop")
        product = self.env["product.product"].create(
            {"name": "Disabled Cart Product", "list_price": 10.0, "is_published": True}
        )
        orders_before = self.env["sale.order"].search_count([])
        # A public session is needed to build a valid CSRF token, otherwise the
        # request is rejected before reaching the controller.
        self.authenticate(None, None)
        response = self.url_open(
            "/shop/cart/update",
            data={
                "product_id": product.id,
                "add_qty": 1,
                "csrf_token": http.Request.csrf_token(self),
            },
            allow_redirects=False,
        )
        self.assertIn(response.status_code, (302, 303))
        self.assertTrue(response.headers.get("Location", "").endswith("/shop"))
        self.assertEqual(self.env["sale.order"].search_count([]), orders_before)

    def test_cart_update_json_is_a_noop(self):
        """The JSON update endpoint answers an empty payload and writes nothing."""
        product = self.env["product.product"].create(
            {"name": "Disabled Cart Product", "list_price": 10.0, "is_published": True}
        )
        orders_before = self.env["sale.order"].search_count([])
        result = self._json_rpc(
            "/shop/cart/update_json", {"product_id": product.id, "add_qty": 1}
        )
        self.assertEqual(result, {})
        self.assertEqual(self.env["sale.order"].search_count([]), orders_before)

    def test_cart_quantity_is_zero(self):
        """The JSON quantity endpoint always answers 0."""
        self.assertEqual(self._json_rpc("/shop/cart/quantity"), 0)
