#############################################################################
#
#    Cybrosys Technologies Pvt. Ltd.
#
#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
#    Author: Vivek @ cybrosys,(odoo@cybrosys.com)
#
#    You can modify it under the terms of the GNU AFFERO
#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
#    (AGPL v3) along with this program.
#    If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from werkzeug.exceptions import NotFound

from odoo import fields, http
from odoo.http import request
from odoo.tools.json import scriptsafe as json_scriptsafe

from odoo.addons.payment import utils as payment_utils
from odoo.addons.website_sale.controllers.main import WebsiteSale


class WebsiteSaleDecimal(WebsiteSale):
    """
    WebsiteSaleDecimal extends WebsiteSale class to update the methods: cart, cart_update,
    cart_update_json and cart_quantity.
    """

    @http.route()
    def cart(self, access_token=None, revive="", **post):
        """
        Main cart management + abandoned cart revival
        access_token: Abandoned cart SO access token
        revive: Revival method when abandoned cart. Can be 'merge' or 'squash'
        """
        order = request.website.sale_get_order()
        if order and order.state != "draft":
            request.session["sale_order_id"] = None
            order = request.website.sale_get_order()
        request.session["website_sale_cart_quantity"] = round(
            sum(order.mapped("website_order_line.product_uom_qty")), 1
        )

        values = {}
        if access_token:
            abandoned_order = (
                request.env["sale.order"]
                .sudo()
                .search([("access_token", "=", access_token)], limit=1)
            )
            if not abandoned_order:
                raise NotFound()
            if abandoned_order.state != "draft":
                values.update({"abandoned_proceed": True})
            elif revive == "squash" or (
                revive == "merge" and not request.session.get("sale_order_id")
            ):
                request.session["sale_order_id"] = abandoned_order.id
                return request.redirect("/shop/cart")
            elif revive == "merge":
                abandoned_order.order_line.write(
                    {"order_id": request.session["sale_order_id"]}
                )
                abandoned_order.action_cancel()
            elif abandoned_order.id != request.session.get("sale_order_id"):
                values.update({"access_token": abandoned_order.access_token})

        values.update(
            {
                "website_sale_order": order,
                "date": fields.Date.today(),
                "suggested_products": [],
            }
        )
        if order:
            order.order_line.filtered(lambda l: not l.product_id.active).unlink()
            values["suggested_products"] = order._cart_accessories()
            values.update(self._get_express_shop_payment_values(order))

        if post.get("type") == "popover":
            # force no-cache so IE11 doesn't cache this XHR
            return request.render(
                "website_sale.cart_popover",
                values,
                headers={"Cache-Control": "no-cache"},
            )

        return request.render("website_sale.cart", values)

    @http.route()
    def cart_update(
        self,
        product_id,
        add_qty=1,
        set_qty=0,
        product_custom_attribute_values=None,
        no_variant_attribute_values=None,
        express=False,
        **kwargs
    ):
        """This route is called when adding a product to cart (no options)."""
        sale_order = request.website.sale_get_order(force_create=True)
        if sale_order.state != "draft":
            request.session["sale_order_id"] = None
            sale_order = request.website.sale_get_order(force_create=True)

        if product_custom_attribute_values:
            product_custom_attribute_values = json_scriptsafe.loads(
                product_custom_attribute_values
            )

        if no_variant_attribute_values:
            no_variant_attribute_values = json_scriptsafe.loads(
                no_variant_attribute_values
            )

        sale_order._cart_update(
            product_id=int(product_id),
            add_qty=add_qty,
            set_qty=set_qty,
            product_custom_attribute_values=product_custom_attribute_values,
            no_variant_attribute_values=no_variant_attribute_values,
            **kwargs
        )
        request.session["website_sale_cart_quantity"] = round(
            sum(sale_order.mapped("website_order_line.product_uom_qty")), 1
        )

        if express:
            return request.redirect("/shop/checkout?express=1")

        return request.redirect("/shop/cart")

    @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_values=None,
        **kw
    ):
        """
        This route is called :
            - When changing quantity from the cart.
            - When adding a product from the wishlist.
            - When adding a product to cart on the same page
            (without redirection).
        """
        order = request.website.sale_get_order(force_create=True)
        if order.state != "draft":
            request.website.sale_reset()
            if kw.get("force_create"):
                order = request.website.sale_get_order(force_create=True)
            else:
                return {}

        if product_custom_attribute_values:
            product_custom_attribute_values = json_scriptsafe.loads(
                product_custom_attribute_values
            )

        if no_variant_attribute_values:
            no_variant_attribute_values = json_scriptsafe.loads(
                no_variant_attribute_values
            )

        values = order._cart_update(
            product_id=product_id,
            line_id=line_id,
            add_qty=add_qty,
            set_qty=set_qty,
            product_custom_attribute_values=product_custom_attribute_values,
            no_variant_attribute_values=no_variant_attribute_values,
            **kw
        )
        request.session["website_sale_cart_quantity"] = round(
            sum(order.mapped("website_order_line.product_uom_qty")), 1
        )

        if not order.cart_quantity:
            request.website.sale_reset()
            return values

        values["cart_quantity"] = round(
            sum(order.mapped("website_order_line.product_uom_qty")), 1
        )
        values["minor_amount"] = (
            payment_utils.to_minor_currency_units(
                order.amount_total, order.currency_id
            ),
        )
        values["amount"] = order.amount_total

        if not display:
            return values

        values["website_sale.cart_lines"] = request.env["ir.ui.view"]._render_template(
            "website_sale.cart_lines",
            {
                "website_sale_order": order,
                "date": fields.Date.today(),
                "suggested_products": order._cart_accessories(),
            },
        )
        values["website_sale.short_cart_summary"] = request.env[
            "ir.ui.view"
        ]._render_template(
            "website_sale.short_cart_summary", {"website_sale_order": order}
        )
        return values

    @http.route()
    def cart_quantity(self):
        """
        This method updates the cart quantity count in the session based on the order's website order lines.
        """
        if "website_sale_cart_quantity" not in request.session:
            return request.website.sale_get_order().mapped(
                "website_order_line.product_uom_qty"
            )
        return request.session["website_sale_cart_quantity"]
