# Copyright (C) 2020: Criptomart (https://criptomart.net)
# @author Santi Noreña (<santi@criptomart.net>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api
from odoo import fields
from odoo import models
from odoo.tools import float_compare


class ProductTemplate(models.Model):
    """Product template with computed fields to product.product.

    All main fields and logic are now in product.product.
    These computed fields allow views on product.template to continue working.
    For templates with a single variant, reads/writes directly from/to the variant.
    For templates with multiple variants, uses the first variant.
    """

    _inherit = "product.template"

    # Computed fields that delegate to product.product variants
    last_purchase_price_updated = fields.Boolean(
        string="Last purchase price updated",
        compute="_compute_last_purchase_price_updated",
        inverse="_inverse_last_purchase_price_updated",
        search="_search_last_purchase_price_updated",
        store=True,
        company_dependent=False,
    )
    list_price_theoritical = fields.Float(
        string="Theoritical price",
        compute="_compute_list_price_theoritical",
        inverse="_inverse_list_price_theoritical",
        search="_search_list_price_theoritical",
        store=True,
        company_dependent=False,
    )
    last_purchase_price_received = fields.Float(
        string="Last purchase price",
        compute="_compute_last_purchase_price_received",
        inverse="_inverse_last_purchase_price_received",
        search="_search_last_purchase_price_received",
        store=True,
        company_dependent=False,
    )
    last_purchase_price_compute_type = fields.Selection(
        [
            ("without_discounts", "Without discounts"),
            ("with_discount", "First discount"),
            ("with_two_discounts", "Double discount"),
            ("with_three_discounts", "Triple discount"),
            ("manual_update", "Manual update"),
        ],
        string="Last purchase price calculation type",
        compute="_compute_last_purchase_price_compute_type",
        inverse="_inverse_last_purchase_price_compute_type",
        search="_search_last_purchase_price_compute_type",
        store=True,
        company_dependent=False,
    )

    # Alias for backward compatibility with pricelist base price computation
    last_purchase_price = fields.Float(
        compute="_compute_last_purchase_price",
        search="_search_last_purchase_price",
        store=True,
        company_dependent=False,
    )

    @api.depends("product_variant_ids.last_purchase_price_updated")
    def _compute_last_purchase_price_updated(self):
        for template in self:
            template.last_purchase_price_updated = (
                template.product_variant_ids[:1].last_purchase_price_updated
                if template.product_variant_ids
                else False
            )

    def _inverse_last_purchase_price_updated(self):
        for template in self:
            if template.product_variant_ids:
                template.product_variant_ids.write(
                    {
                        "last_purchase_price_updated": template.last_purchase_price_updated
                    }
                )

    def _search_last_purchase_price_updated(self, operator, value):
        return [("product_variant_ids.last_purchase_price_updated", operator, value)]

    @api.depends("product_variant_ids.list_price_theoritical")
    def _compute_list_price_theoritical(self):
        for template in self:
            if template.product_variant_ids:
                value = template.product_variant_ids[:1].list_price_theoritical
                # Ensure we always return a valid float (never False/None/dict)
                template.list_price_theoritical = float(value or 0.0)
            else:
                template.list_price_theoritical = 0.0

    def _inverse_list_price_theoritical(self):
        for template in self:
            if template.product_variant_ids:
                template.product_variant_ids.write(
                    {"list_price_theoritical": template.list_price_theoritical}
                )

    def _search_list_price_theoritical(self, operator, value):
        return [("product_variant_ids.list_price_theoritical", operator, value)]

    @api.depends("product_variant_ids.last_purchase_price_received")
    def _compute_last_purchase_price_received(self):
        for template in self:
            if template.product_variant_ids:
                value = template.product_variant_ids[:1].last_purchase_price_received
                # Ensure we always return a valid float (never False/None/dict)
                template.last_purchase_price_received = float(value or 0.0)
            else:
                template.last_purchase_price_received = 0.0

    def _inverse_last_purchase_price_received(self):
        for template in self:
            if template.product_variant_ids:
                template.product_variant_ids.write(
                    {
                        "last_purchase_price_received": template.last_purchase_price_received
                    }
                )

    def _search_last_purchase_price_received(self, operator, value):
        return [("product_variant_ids.last_purchase_price_received", operator, value)]

    @api.depends("product_variant_ids.last_purchase_price_compute_type")
    def _compute_last_purchase_price_compute_type(self):
        for template in self:
            template.last_purchase_price_compute_type = (
                template.product_variant_ids[:1].last_purchase_price_compute_type
                if template.product_variant_ids
                else "without_discounts"
            )

    def _inverse_last_purchase_price_compute_type(self):
        for template in self:
            if template.product_variant_ids:
                template.product_variant_ids.write(
                    {
                        "last_purchase_price_compute_type": template.last_purchase_price_compute_type
                    }
                )

    def _search_last_purchase_price_compute_type(self, operator, value):
        return [
            ("product_variant_ids.last_purchase_price_compute_type", operator, value)
        ]

    @api.depends("last_purchase_price_received")
    def _compute_last_purchase_price(self):
        """Alias for backward compatibility with pricelist computations."""
        for template in self:
            # Ensure we always return a valid float (never False/None/dict)
            template.last_purchase_price = float(
                template.last_purchase_price_received or 0.0
            )

    def _search_last_purchase_price(self, operator, value):
        return [("last_purchase_price_received", operator, value)]

    def _compute_theoritical_price(self):
        """Delegate to product variants."""
        return self.product_variant_ids._compute_theoritical_price()

    def action_update_list_price(self):
        """Delegate to product variants."""
        return self.product_variant_ids.action_update_list_price()

    def action_sync_purchase_price_from_supplierinfo(self):
        """Bulk-correct last_purchase_price_received from the main supplierinfo,
        applying discounts according to last_purchase_price_compute_type."""
        updated = 0
        skipped_manual = 0
        skipped_no_seller = 0

        for product in self.product_variant_ids:
            if product.last_purchase_price_compute_type == "manual_update":
                skipped_manual += 1
                continue
            seller = product._get_main_supplierinfo()
            if not seller:
                skipped_no_seller += 1
                continue
            net_price = product._compute_supplierinfo_net_price(seller)
            if (
                float_compare(
                    product.last_purchase_price_received, net_price, precision_digits=2
                )
                != 0
            ):
                product.write({"last_purchase_price_received": net_price})
                product._recompute_theoritical_price_safe()
                updated += 1

        parts = []
        if updated:
            parts.append(self.env._("Updated: %(n)s", n=updated))
        if skipped_manual:
            parts.append(self.env._("Skipped (manual update): %(n)s", n=skipped_manual))
        if skipped_no_seller:
            parts.append(
                self.env._("Skipped (no supplier): %(n)s", n=skipped_no_seller)
            )
        message = "\n".join(parts) if parts else self.env._("Nothing to correct.")

        return {
            "type": "ir.actions.client",
            "tag": "display_notification",
            "params": {
                "title": self.env._("Sync Purchase Price"),
                "message": message,
                "type": "success" if updated else "warning",
                "sticky": False,
                "next": {"type": "ir.actions.act_window_close"},
            },
        }
