# Fusion Accounting - Debit Note Creation
# Copyright (C) 2026 Nexa Systems Inc. (https://nexasystems.ca)
# Original implementation for the Fusion Accounting module.
#
# Extends account.move with the ability to create debit notes from
# existing invoices.  A debit note copies the invoice lines with
# reversed sign and links back to the original document.

import logging

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

_logger = logging.getLogger(__name__)


class FusionDebitNote(models.Model):
    """Extends account.move with debit note creation from invoices.

    A *debit note* is an additional charge issued to a customer or
    received from a vendor.  Unlike a credit note (which reduces the
    amount owed), a debit note increases it.

    This implementation:
      - Copies all product lines from the source invoice
      - Creates a new invoice of the same type (not reversed)
      - Links the debit note back to the original document
    """

    _inherit = 'account.move'

    # =====================================================================
    # Fields
    # =====================================================================

    fusion_debit_note_origin_id = fields.Many2one(
        comodel_name='account.move',
        string="Debit Note Origin",
        copy=False,
        readonly=True,
        index=True,
        help="The original invoice from which this debit note was created.",
    )
    fusion_debit_note_ids = fields.One2many(
        comodel_name='account.move',
        inverse_name='fusion_debit_note_origin_id',
        string="Debit Notes",
        copy=False,
        readonly=True,
        help="Debit notes created from this invoice.",
    )
    fusion_debit_note_count = fields.Integer(
        string="Debit Note Count",
        compute='_compute_debit_note_count',
    )

    # =====================================================================
    # Computed Fields
    # =====================================================================

    @api.depends('fusion_debit_note_ids')
    def _compute_debit_note_count(self):
        for move in self:
            move.fusion_debit_note_count = len(move.fusion_debit_note_ids)

    # =====================================================================
    # Debit Note Creation
    # =====================================================================

    def action_create_debit_note(self):
        """Create a debit note from the current invoice.

        The debit note is a new invoice document with the same type as
        the original.  All product lines are copied.  The amounts remain
        positive (this is an additional charge, not a reversal).

        Supported source types:
          - Customer Invoice (out_invoice)  →  Customer Debit Note (out_invoice)
          - Vendor Bill (in_invoice)        →  Vendor Debit Note (in_invoice)

        :returns: action dict to open the newly created debit note
        :raises UserError: if the move type is unsupported
        """
        self.ensure_one()

        if self.move_type not in ('out_invoice', 'in_invoice'):
            raise UserError(_(
                "Debit notes can only be created from customer invoices "
                "or vendor bills."
            ))

        if self.state == 'draft':
            raise UserError(_(
                "Please confirm the invoice before creating a debit note."
            ))

        # Build line values from original invoice
        line_vals = []
        for line in self.invoice_line_ids.filtered(
            lambda l: l.display_type == 'product'
        ):
            line_vals.append(Command.create({
                'name': _("Debit Note: %s", line.name or ''),
                'product_id': line.product_id.id if line.product_id else False,
                'product_uom_id': line.product_uom_id.id if line.product_uom_id else False,
                'quantity': line.quantity,
                'price_unit': line.price_unit,
                'discount': line.discount,
                'tax_ids': [Command.set(line.tax_ids.ids)],
                'analytic_distribution': line.analytic_distribution,
                'account_id': line.account_id.id,
            }))

        # Copy section and note lines for context
        for line in self.invoice_line_ids.filtered(
            lambda l: l.display_type in ('line_section', 'line_note')
        ):
            line_vals.append(Command.create({
                'display_type': line.display_type,
                'name': line.name,
                'sequence': line.sequence,
            }))

        if not line_vals:
            raise UserError(_(
                "The invoice has no lines to copy for the debit note."
            ))

        debit_note_vals = {
            'move_type': self.move_type,
            'partner_id': self.partner_id.id,
            'journal_id': self.journal_id.id,
            'currency_id': self.currency_id.id,
            'company_id': self.company_id.id,
            'invoice_date': fields.Date.context_today(self),
            'ref': _("DN: %s", self.name),
            'narration': _("Debit Note for %s", self.name),
            'fiscal_position_id': self.fiscal_position_id.id if self.fiscal_position_id else False,
            'invoice_payment_term_id': self.invoice_payment_term_id.id if self.invoice_payment_term_id else False,
            'fusion_debit_note_origin_id': self.id,
            'invoice_line_ids': line_vals,
        }

        debit_note = self.env['account.move'].create(debit_note_vals)

        _logger.info(
            "Fusion Debit Note: created %s (id=%s) from %s (id=%s)",
            debit_note.name, debit_note.id, self.name, self.id,
        )

        # Return action to view the debit note
        if self.move_type == 'out_invoice':
            action_ref = 'account.action_move_out_invoice_type'
        else:
            action_ref = 'account.action_move_in_invoice_type'

        return {
            'type': 'ir.actions.act_window',
            'res_model': 'account.move',
            'res_id': debit_note.id,
            'view_mode': 'form',
            'target': 'current',
            'name': _("Debit Note"),
        }

    # =====================================================================
    # View Related Debit Notes
    # =====================================================================

    def action_view_debit_notes(self):
        """Open the list of debit notes created from this invoice."""
        self.ensure_one()
        debit_notes = self.fusion_debit_note_ids

        if len(debit_notes) == 1:
            return {
                'type': 'ir.actions.act_window',
                'res_model': 'account.move',
                'res_id': debit_notes.id,
                'view_mode': 'form',
                'target': 'current',
                'name': _("Debit Note"),
            }

        return {
            'type': 'ir.actions.act_window',
            'res_model': 'account.move',
            'domain': [('id', 'in', debit_notes.ids)],
            'view_mode': 'list,form',
            'target': 'current',
            'name': _("Debit Notes"),
        }
