"""
Fusion Accounting - Loan CSV Import Wizard

Allows bulk-importing loan records from a CSV file with the columns:
name, principal, rate, term, start_date.

After import, each loan is created in Draft state so the user can
review parameters and compute the amortization schedule manually.
"""

import base64
import csv
import io
from datetime import datetime

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


class FusionLoanImportWizard(models.TransientModel):
    """Transient wizard to import loans from a CSV file.

    Expected CSV columns (header required):
        - name          : Loan reference / description
        - principal     : Principal amount (float)
        - rate          : Annual interest rate in percent (float)
        - term          : Loan term in months (integer)
        - start_date    : Start date in YYYY-MM-DD format
    """
    _name = 'fusion.loan.import.wizard'
    _description = 'Import Loans from CSV'

    csv_file = fields.Binary(
        string='CSV File',
        required=True,
        help="Upload a CSV file with columns: name, principal, rate, term, start_date.",
    )
    csv_filename = fields.Char(string='Filename')
    journal_id = fields.Many2one(
        'account.journal',
        string='Default Journal',
        required=True,
        domain="[('type', 'in', ['bank', 'general'])]",
        help="Journal to assign to all imported loans.",
    )
    loan_account_id = fields.Many2one(
        'account.account',
        string='Default Loan Account',
        required=True,
        help="Liability account for imported loans.",
    )
    interest_account_id = fields.Many2one(
        'account.account',
        string='Default Interest Account',
        required=True,
        help="Expense account for interest on imported loans.",
    )
    partner_id = fields.Many2one(
        'res.partner',
        string='Default Lender',
        required=True,
        help="Default lender assigned when the CSV doesn't specify one.",
    )
    payment_frequency = fields.Selection(
        selection=[
            ('monthly', 'Monthly'),
            ('quarterly', 'Quarterly'),
            ('semi_annually', 'Semi-Annually'),
            ('annually', 'Annually'),
        ],
        string='Default Payment Frequency',
        default='monthly',
        required=True,
    )
    amortization_method = fields.Selection(
        selection=[
            ('french', 'French (Equal Payments)'),
            ('linear', 'Linear (Equal Principal)'),
        ],
        string='Default Amortization Method',
        default='french',
        required=True,
    )
    auto_compute = fields.Boolean(
        string='Auto-Compute Schedules',
        default=False,
        help="Automatically compute the amortization schedule after import.",
    )

    # Required CSV header columns
    _REQUIRED_COLUMNS = {'name', 'principal', 'rate', 'term', 'start_date'}

    def action_import(self):
        """Parse the uploaded CSV and create loan records."""
        self.ensure_one()

        if not self.csv_file:
            raise UserError(_("Please upload a CSV file."))

        # Decode file
        try:
            raw = base64.b64decode(self.csv_file)
            text = raw.decode('utf-8-sig')  # handles BOM gracefully
        except Exception as exc:
            raise UserError(
                _("Unable to read the file. Ensure it is a valid UTF-8 CSV. (%s)", exc)
            )

        reader = csv.DictReader(io.StringIO(text))

        # Validate headers
        if not reader.fieldnames:
            raise UserError(_("The CSV file appears to be empty."))
        headers = {h.strip().lower() for h in reader.fieldnames}
        missing = self._REQUIRED_COLUMNS - headers
        if missing:
            raise UserError(
                _("Missing required CSV columns: %s", ', '.join(sorted(missing)))
            )

        # Build column name mapping (stripped & lowered -> original)
        col_map = {h.strip().lower(): h for h in reader.fieldnames}

        loan_vals_list = []
        errors = []
        for row_num, row in enumerate(reader, start=2):
            try:
                name = (row.get(col_map['name']) or '').strip()
                principal = float(row.get(col_map['principal'], 0))
                rate = float(row.get(col_map['rate'], 0))
                term = int(row.get(col_map['term'], 0))
                start_raw = (row.get(col_map['start_date']) or '').strip()
                start_date = datetime.strptime(start_raw, '%Y-%m-%d').date()
            except (ValueError, TypeError) as exc:
                errors.append(_("Row %s: %s", row_num, exc))
                continue

            if principal <= 0:
                errors.append(_("Row %s: principal must be positive.", row_num))
                continue
            if term <= 0:
                errors.append(_("Row %s: term must be positive.", row_num))
                continue

            loan_vals_list.append({
                'name': name or _('New'),
                'partner_id': self.partner_id.id,
                'journal_id': self.journal_id.id,
                'loan_account_id': self.loan_account_id.id,
                'interest_account_id': self.interest_account_id.id,
                'principal_amount': principal,
                'interest_rate': rate,
                'loan_term': term,
                'start_date': start_date,
                'payment_frequency': self.payment_frequency,
                'amortization_method': self.amortization_method,
            })

        if errors:
            raise UserError(
                _("Import errors:\n%s", '\n'.join(str(e) for e in errors))
            )
        if not loan_vals_list:
            raise UserError(_("No valid loan rows found in the CSV file."))

        loans = self.env['fusion.loan'].create(loan_vals_list)

        if self.auto_compute:
            for loan in loans:
                loan.compute_amortization_schedule()

        # Return the newly created loans
        return {
            'name': _('Imported Loans'),
            'type': 'ir.actions.act_window',
            'res_model': 'fusion.loan',
            'view_mode': 'list,form',
            'domain': [('id', 'in', loans.ids)],
            'target': 'current',
        }
