"""
Fusion Accounting - Loan Amortization Line

Each record represents a single installment in a loan's amortization
schedule, tracking principal, interest, remaining balance, and the
link to the corresponding journal entry once paid.
"""

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


class FusionLoanLine(models.Model):
    """Single installment of a loan amortization schedule.

    Created in bulk by :meth:`fusion.loan.compute_amortization_schedule`
    and individually paid via :meth:`action_create_entry` which posts
    a journal entry debiting the loan liability and interest expense,
    and crediting the bank / payment account.
    """
    _name = 'fusion.loan.line'
    _description = 'Loan Amortization Line'
    _order = 'sequence, id'

    # ------------------------------------------------------------------
    # Parent link
    # ------------------------------------------------------------------
    loan_id = fields.Many2one(
        'fusion.loan',
        string='Loan',
        required=True,
        ondelete='cascade',
        index=True,
    )

    # ------------------------------------------------------------------
    # Schedule fields
    # ------------------------------------------------------------------
    sequence = fields.Integer(
        string='#',
        required=True,
        help="Installment number in the amortization schedule.",
    )
    date = fields.Date(
        string='Due Date',
        required=True,
    )
    principal_amount = fields.Monetary(
        string='Principal',
        currency_field='currency_id',
        help="Portion of the payment that reduces the outstanding balance.",
    )
    interest_amount = fields.Monetary(
        string='Interest',
        currency_field='currency_id',
        help="Interest charged for this period.",
    )
    total_payment = fields.Monetary(
        string='Total Payment',
        currency_field='currency_id',
        help="Sum of principal and interest for this installment.",
    )
    remaining_balance = fields.Monetary(
        string='Remaining Balance',
        currency_field='currency_id',
        help="Outstanding principal after this installment.",
    )

    # ------------------------------------------------------------------
    # Status
    # ------------------------------------------------------------------
    is_paid = fields.Boolean(
        string='Paid',
        default=False,
        copy=False,
    )
    move_id = fields.Many2one(
        'account.move',
        string='Journal Entry',
        copy=False,
        readonly=True,
        help="The posted journal entry recording this installment payment.",
    )

    # ------------------------------------------------------------------
    # Related / helper
    # ------------------------------------------------------------------
    currency_id = fields.Many2one(
        related='loan_id.currency_id',
        store=True,
    )
    company_id = fields.Many2one(
        related='loan_id.company_id',
        store=True,
    )
    loan_state = fields.Selection(
        related='loan_id.state',
        string='Loan Status',
    )

    # ==================== Business Methods ====================

    def action_create_entry(self):
        """Create and post the journal entry for this loan installment.

        Debits:
            - Loan liability account  (principal portion)
            - Interest expense account (interest portion)
        Credits:
            - Journal default account / bank (total payment)
        """
        self.ensure_one()
        if self.is_paid:
            raise UserError(
                _("Installment #%s is already paid.", self.sequence)
            )
        if self.loan_id.state != 'running':
            raise UserError(
                _("Entries can only be created for running loans.")
            )

        loan = self.loan_id
        move_vals = {
            'journal_id': loan.journal_id.id,
            'date': self.date,
            'ref': _('%(loan)s - Installment #%(seq)s',
                     loan=loan.name, seq=self.sequence),
            'fusion_loan_id': loan.id,
            'line_ids': [
                # Debit: reduce loan liability
                Command.create({
                    'account_id': loan.loan_account_id.id,
                    'debit': self.principal_amount,
                    'credit': 0.0,
                    'partner_id': loan.partner_id.id,
                    'name': _('%(loan)s - Principal #%(seq)s',
                             loan=loan.name, seq=self.sequence),
                }),
                # Debit: interest expense
                Command.create({
                    'account_id': loan.interest_account_id.id,
                    'debit': self.interest_amount,
                    'credit': 0.0,
                    'partner_id': loan.partner_id.id,
                    'name': _('%(loan)s - Interest #%(seq)s',
                             loan=loan.name, seq=self.sequence),
                }),
                # Credit: bank / payment
                Command.create({
                    'account_id': loan.journal_id.default_account_id.id,
                    'debit': 0.0,
                    'credit': self.total_payment,
                    'partner_id': loan.partner_id.id,
                    'name': _('%(loan)s - Payment #%(seq)s',
                             loan=loan.name, seq=self.sequence),
                }),
            ],
        }
        move = self.env['account.move'].create(move_vals)
        move.action_post()

        self.write({
            'is_paid': True,
            'move_id': move.id,
        })
        return True
