# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from urllib.parse import urlencode

from odoo import http
from odoo.addons.website_sale.controllers.main import WebsiteSale
from odoo.http import request

SIGNUP_FLAG = "membership_signup=1"


class WebsiteSaleMembershipSignup(WebsiteSale):

    def _membership_signup_is_required(self, product_id):
        """Return True iff an anonymous visitor adding `product_id` to the
        cart must be redirected to /web/signup first.
        """
        website = request.website
        return website._membership_signup_required_for(
            product_id, request.env.user._is_public()
        )

    def _membership_signup_redirect_url(self, product_id):
        """Build the `/web/signup?membership_signup=1&redirect=<product_url>`
        URL preserving the current language.
        """
        product = request.env["product.product"].browse(int(product_id))
        tmpl = product.product_tmpl_id
        product_url = "/shop/%s" % request.env["ir.http"]._slug(tmpl)
        query = urlencode({"membership_signup": "1", "redirect": product_url})
        return "/web/signup?%s" % query

    def _membership_signup_mark_session(self, product_id):
        request.session["membership_signup_active"] = True
        request.session["membership_signup_product_id"] = int(product_id)

    @http.route()
    def cart_update(
        self, product_id, add_qty=1, set_qty=0,
        product_custom_attribute_values=None,
        no_variant_attribute_value_ids=None, **kwargs
    ):
        if self._membership_signup_is_required(product_id):
            self._membership_signup_mark_session(product_id)
            return request.redirect(self._membership_signup_redirect_url(product_id))
        return super().cart_update(
            product_id=product_id, add_qty=add_qty, set_qty=set_qty,
            product_custom_attribute_values=product_custom_attribute_values,
            no_variant_attribute_value_ids=no_variant_attribute_value_ids,
            **kwargs
        )

    @http.route()
    def cart_update_json(
        self, product_id, line_id=None, add_qty=None, set_qty=None, display=True,
        product_custom_attribute_values=None, no_variant_attribute_value_ids=None, **kwargs
    ):
        if self._membership_signup_is_required(product_id):
            self._membership_signup_mark_session(product_id)
            # The JSON route cannot perform an HTTP redirect on its own; signal
            # the frontend so it can navigate to the signup URL. The standard
            # "Add to Cart" on a product page uses /shop/cart/update (http),
            # which is the primary path for this flow (RF-01). The JSON route
            # covers add-to-cart from snippets/wishlist on the same page
            # (`stayOnPageOption` / `o_we_buy_now` express).
            #
            # The JS handler in
            # `static/src/js/website_membership_signup_required.js` reads
            # `data.force_redirect` and navigates to it. The other keys are
            # NOT consumed by our handler: they exist to keep the core's
            # `cartHandlerMixin._addToCartInPage` (in
            # `website_sale/static/src/js/website_sale_utils.js`) from crashing.
            # That method does, in order:
            #     if (data.cart_quantity && ...) updateCartNavBar(data);
            #     showCartNotification(call, data.notification_info);
            # `showCartNotification` accesses `props.lines` and `props.warning`
            # on `data.notification_info`; if it is `undefined` (as it was in
            # the first iteration, which only returned `{force_redirect: ...}`)
            # the access raises `TypeError: can't access property "lines",
            # props is undefined` and the redirect never fires.
            #
            # Shape (mirrors the empty-cart branch in
            # `WebsiteSaleController.cart_update_json`):
            #     cart_quantity = 0  -> falsy, so `updateCartNavBar` is skipped.
            #     notification_info = {lines: [], warning: ""}
            #         -> `showCartNotification` no-ops on both empty fields.
            return {
                "force_redirect": self._membership_signup_redirect_url(product_id),
                "cart_quantity": 0,
                "notification_info": {"lines": [], "warning": ""},
            }
        return super().cart_update_json(
            product_id=product_id, line_id=line_id, add_qty=add_qty,
            set_qty=set_qty, display=display,
            product_custom_attribute_values=product_custom_attribute_values,
            no_variant_attribute_value_ids=no_variant_attribute_value_ids,
            **kwargs
        )

    def _get_mandatory_address_fields(self, country_sudo):
        # EMES: the phone field is not mandatory at checkout, for any flow
        # (membership or regular). The core's default set in
        # `website_sale/controllers/main.py:_get_mandatory_address_fields`
        # includes 'phone' alongside name/street/city/country_id. Removing it
        # here cascades to both billing and delivery mandatory fields (both
        # delegates to this method) and propagates to the frontend: the
        # hidden `required_fields` input sent to the address form no longer
        # lists 'phone', so `address.js` neither marks the input as
        # `:required` nor shows the red asterisk, and the server-side
        # `_check_billing_address` / `_check_delivery_address` no longer
        # reject empty phones.
        fields = super()._get_mandatory_address_fields(country_sudo)
        fields.discard("phone")
        return fields

    def _get_mandatory_fields(self):
        # Portal's `_get_mandatory_fields` (in
        # `portal/controllers/portal.py`) returns
        # `["name", "phone", "email", "street", "city", "country_id"]`,
        # and `website_sale`'s `_get_mandatory_billing_address_fields`
        # UNIONS that set with the one from `_get_mandatory_address_fields`.
        # So even after we drop 'phone' from the address set above, the
        # portal set re-adds it for billing. We need to drop it here too.
        fields = list(super()._get_mandatory_fields())
        return [f for f in fields if f != "phone"]