# Copyright 2024 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from collections import defaultdict

from odoo import _, api, fields, models
from odoo.exceptions import UserError


class AccountMoveRappelWizard(models.TransientModel):
    """Wizard to generate rappel commission (sale) invoices from selected vendor bills.

    One sale invoice is created per vendor. Each original bill becomes one invoice
    line whose amount is computed as: taxable_base × commission_rate / 100.
    """

    _name = "account.move.rappel.wizard"
    _description = "Create Rappel Commission Invoice"

    move_ids = fields.Many2many(
        comodel_name="account.move",
        string="Vendor Bills",
        readonly=True,
    )
    invoice_date = fields.Date(
        string="Invoice Date",
        default=fields.Date.context_today,
        required=True,
    )
    company_id = fields.Many2one(
        comodel_name="res.company",
        default=lambda self: self.env.company,
        required=True,
    )
    journal_id = fields.Many2one(
        comodel_name="account.journal",
        string="Journal",
        domain="[('type', '=', 'sale'), ('company_id', '=', company_id)]",
        required=True,
    )
    product_id = fields.Many2one(
        comodel_name="product.product",
        string="Commission Product",
        required=True,
    )

    @api.model
    def default_get(self, fields_list):
        res = super().default_get(fields_list)
        company = self.env.company
        active_ids = self.env.context.get("active_ids", [])
        moves = self.env["account.move"].browse(active_ids)

        # Filter only posted vendor bills and refunds
        valid_moves = moves.filtered(
            lambda m: m.move_type in ("in_invoice", "in_refund")
            and m.state == "posted"
        )
        if not valid_moves:
            raise UserError(
                _(
                    "No posted vendor bills or refunds found in the selection. "
                    "Only posted (validated) vendor bills and refunds can be used to "
                    "create rappel commission invoices."
                )
            )

        # Filter only pending bills
        pending_moves = valid_moves.filtered(lambda m: m.rappel_pending)
        if not pending_moves:
            raise UserError(
                _(
                    "None of the selected vendor bills are pending commission. "
                    "They may have already been commissioned."
                )
            )

        # Warn about bills whose partner has no rappel configured
        no_rappel = pending_moves.filtered(lambda m: not m.partner_id.rappel_commission)
        if no_rappel and len(no_rappel) == len(pending_moves):
            raise UserError(
                _(
                    "None of the selected vendors have the rappel commission enabled. "
                    "Please configure the commission rate on the vendor contact first."
                )
            )

        res.update(
            {
                "move_ids": [(6, 0, pending_moves.ids)],
                "journal_id": company.rappel_journal_id.id or False,
                "product_id": company.rappel_product_id.id or False,
            }
        )
        return res

    def action_create_rappel_invoices(self):
        self.ensure_one()

        if not self.journal_id:
            raise UserError(
                _(
                    "Please select a journal for the rappel commission invoices, or "
                    "configure a default one in Purchase Settings."
                )
            )
        if not self.product_id:
            raise UserError(
                _(
                    "Please select a product for the rappel commission invoices, or "
                    "configure a default one in Purchase Settings."
                )
            )

        # Group eligible bills by partner (only partners with rappel enabled)
        bills_by_partner = defaultdict(lambda: self.env["account.move"])
        for bill in self.move_ids:
            if (
                bill.partner_id.rappel_commission
                and bill.partner_id.rappel_commission_rate
            ):
                bills_by_partner[bill.partner_id] |= bill

        if not bills_by_partner:
            raise UserError(
                _(
                    "None of the selected vendor bills belong to vendors with a rappel "
                    "commission rate configured."
                )
            )

        created_invoices = self.env["account.move"]

        for partner, bills in bills_by_partner.items():
            rate = partner.rappel_commission_rate
            invoice_lines = []

            for bill in bills:
                taxable_base = bill.amount_untaxed
                commission_amount = taxable_base * rate / 100.0
                vendor_ref = bill.ref or bill.name
                if bill.move_type == "in_refund":
                    # Vendor refunds reduce the commission: negate the amount so
                    # the resulting line subtracts from the rappel invoice total.
                    # amount_untaxed is always positive in Odoo, so we flip the
                    # sign here and display a negative base in the description.
                    commission_amount = -commission_amount
                    display_base = -taxable_base
                    name = _(
                        "Rappel commission %(rate)s%% — Refund %(bill)s "
                        "(taxable base: %(base)s %(currency)s)",
                        rate=rate,
                        bill=vendor_ref,
                        base=f"{display_base:,.2f}",
                        currency=bill.currency_id.name,
                    )
                else:
                    name = _(
                        "Rappel commission %(rate)s%% — Bill %(bill)s "
                        "(taxable base: %(base)s %(currency)s)",
                        rate=rate,
                        bill=vendor_ref,
                        base=f"{taxable_base:,.2f}",
                        currency=bill.currency_id.name,
                    )
                invoice_lines.append(
                    (
                        0,
                        0,
                        {
                            "product_id": self.product_id.id,
                            "name": name,
                            "quantity": 1,
                            "price_unit": commission_amount,
                            "tax_ids": [
                                (
                                    6,
                                    0,
                                    self.product_id.taxes_id.filtered(
                                        lambda t: t.company_id == self.company_id
                                    ).ids,
                                )
                            ],
                        },
                    )
                )

            invoice_vals = {
                "move_type": "out_invoice",
                "partner_id": partner.id,
                "invoice_date": self.invoice_date,
                "journal_id": self.journal_id.id,
                "company_id": self.company_id.id,
                "invoice_line_ids": invoice_lines,
                "narration": _(
                    "Rappel commission invoice generated from %d vendor bill(s).",
                    len(bills),
                ),
            }
            created_invoice = self.env["account.move"].create(invoice_vals)
            created_invoices |= created_invoice

            # Mark source bills as commissioned
            bills.write({"rappel_pending": False})

        # Open the created invoices
        if len(created_invoices) == 1:
            return {
                "type": "ir.actions.act_window",
                "res_model": "account.move",
                "res_id": created_invoices.id,
                "view_mode": "form",
                "views": [(False, "form")],
            }
        return {
            "type": "ir.actions.act_window",
            "res_model": "account.move",
            "domain": [("id", "in", created_invoices.ids)],
            "view_mode": "list,form",
            "name": _("Rappel Commission Invoices"),
        }
