# Fusion Accounting - Account Transfer Wizard
# Copyright (C) 2026 Nexa Systems Inc. (https://nexasystems.ca)
# Original implementation for the Fusion Accounting module.
#
# Provides a transient model that creates a journal entry to move
# a balance from one account to another within the same company.

import logging
from datetime import date

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

_logger = logging.getLogger(__name__)


class FusionAccountTransfer(models.TransientModel):
    """Wizard for transferring balances between two accounts.

    Creates a balanced journal entry with one debit line and one credit
    line, effectively moving a specified amount from the source account
    to the destination account.
    """

    _name = 'fusion.account.transfer'
    _description = 'Account Balance Transfer'

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

    company_id = fields.Many2one(
        comodel_name='res.company',
        string="Company",
        required=True,
        default=lambda self: self.env.company,
        readonly=True,
    )
    currency_id = fields.Many2one(
        comodel_name='res.currency',
        string="Currency",
        related='company_id.currency_id',
        readonly=True,
    )
    source_account_id = fields.Many2one(
        comodel_name='account.account',
        string="Source Account",
        required=True,
        domain="[('company_ids', 'in', company_id)]",
        help="The account to transfer funds FROM (will be credited).",
    )
    destination_account_id = fields.Many2one(
        comodel_name='account.account',
        string="Destination Account",
        required=True,
        domain="[('company_ids', 'in', company_id)]",
        help="The account to transfer funds TO (will be debited).",
    )
    amount = fields.Monetary(
        string="Amount",
        required=True,
        currency_field='currency_id',
        help="Amount to transfer between the accounts.",
    )
    journal_id = fields.Many2one(
        comodel_name='account.journal',
        string="Journal",
        required=True,
        domain="[('type', '=', 'general'), ('company_id', '=', company_id)]",
        help="Miscellaneous journal to record the transfer entry.",
    )
    date = fields.Date(
        string="Date",
        required=True,
        default=fields.Date.context_today,
        help="Date of the transfer journal entry.",
    )
    memo = fields.Char(
        string="Memo",
        help="Optional description for the journal entry.",
    )
    partner_id = fields.Many2one(
        comodel_name='res.partner',
        string="Partner",
        help="Optional partner for the journal entry lines.",
    )

    # =====================================================================
    # Constraints
    # =====================================================================

    @api.constrains('source_account_id', 'destination_account_id')
    def _check_different_accounts(self):
        for record in self:
            if record.source_account_id == record.destination_account_id:
                raise ValidationError(
                    _("Source and destination accounts must be different.")
                )

    @api.constrains('amount')
    def _check_positive_amount(self):
        for record in self:
            if record.amount <= 0:
                raise ValidationError(
                    _("Transfer amount must be greater than zero.")
                )

    # =====================================================================
    # Default Values
    # =====================================================================

    @api.model
    def default_get(self, fields_list):
        """Set default journal to the company's miscellaneous journal."""
        defaults = super().default_get(fields_list)
        if 'journal_id' not in defaults:
            misc_journal = self.env['account.journal'].search([
                ('type', '=', 'general'),
                ('company_id', '=', self.env.company.id),
            ], limit=1)
            if misc_journal:
                defaults['journal_id'] = misc_journal.id
        return defaults

    # =====================================================================
    # Action
    # =====================================================================

    def action_transfer(self):
        """Create a journal entry moving balance between accounts.

        Generates a balanced journal entry:
          - Credit line on the source account
          - Debit line on the destination account

        :returns: action dict pointing to the created journal entry
        :raises UserError: if required fields are missing or invalid
        """
        self.ensure_one()

        if not self.source_account_id or not self.destination_account_id:
            raise UserError(_("Both source and destination accounts are required."))

        if self.amount <= 0:
            raise UserError(_("The transfer amount must be positive."))

        ref = self.memo or _("Account Transfer: %s → %s",
                             self.source_account_id.display_name,
                             self.destination_account_id.display_name)

        move_vals = {
            'journal_id': self.journal_id.id,
            'date': self.date,
            'ref': ref,
            'company_id': self.company_id.id,
            'move_type': 'entry',
            'line_ids': [
                # Credit the source account
                Command.create({
                    'account_id': self.source_account_id.id,
                    'name': ref,
                    'debit': 0.0,
                    'credit': self.amount,
                    'partner_id': self.partner_id.id if self.partner_id else False,
                }),
                # Debit the destination account
                Command.create({
                    'account_id': self.destination_account_id.id,
                    'name': ref,
                    'debit': self.amount,
                    'credit': 0.0,
                    'partner_id': self.partner_id.id if self.partner_id else False,
                }),
            ],
        }

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

        _logger.info(
            "Fusion Account Transfer: created journal entry %s (id=%s) "
            "for %.2f from %s to %s",
            move.name, move.id, self.amount,
            self.source_account_id.code,
            self.destination_account_id.code,
        )

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