package models

import (
	"fmt"
	"math"

	"odoo-go/pkg/orm"
)

// initAccountCashRounding registers account.cash.rounding — rounding rules for invoices.
// Mirrors: odoo/addons/account/models/account_cash_rounding.py
//
// Used to round invoice totals to the nearest increment (e.g. 0.05 CHF in Switzerland).
// Two strategies:
//   - "biggest_tax": add the rounding difference to the biggest tax line
//   - "add_invoice_line": add a separate rounding line
func initAccountCashRounding() {
	m := orm.NewModel("account.cash.rounding", orm.ModelOpts{
		Description: "Cash Rounding",
		Order:       "name",
	})

	m.AddFields(
		orm.Char("name", orm.FieldOpts{String: "Name", Required: true, Translate: true}),
		orm.Float("rounding", orm.FieldOpts{
			String: "Rounding Precision", Required: true, Default: 0.01,
			Help:   "Represent the non-zero value smallest coinage (e.g. 0.05)",
		}),
		orm.Selection("strategy", []orm.SelectionItem{
			{Value: "biggest_tax", Label: "Modify tax amount"},
			{Value: "add_invoice_line", Label: "Add a rounding line"},
		}, orm.FieldOpts{String: "Rounding Strategy", Default: "add_invoice_line", Required: true}),
		orm.Many2one("profit_account_id", "account.account", orm.FieldOpts{
			String: "Profit Account",
			Help:   "Account for the rounding line when strategy is add_invoice_line (rounding up)",
		}),
		orm.Many2one("loss_account_id", "account.account", orm.FieldOpts{
			String: "Loss Account",
			Help:   "Account for the rounding line when strategy is add_invoice_line (rounding down)",
		}),
		orm.Selection("rounding_method", []orm.SelectionItem{
			{Value: "UP", Label: "Up"},
			{Value: "DOWN", Label: "Down"},
			{Value: "HALF-UP", Label: "Half-Up"},
		}, orm.FieldOpts{String: "Rounding Method", Default: "HALF-UP", Required: true}),
		orm.Many2one("company_id", "res.company", orm.FieldOpts{String: "Company"}),
	)

	// compute_rounding: round an amount according to this rounding rule.
	// Returns the rounded amount and the difference.
	// Mirrors: odoo/addons/account/models/account_cash_rounding.py round()
	m.RegisterMethod("compute_rounding", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		if len(args) < 1 {
			return nil, fmt.Errorf("account: compute_rounding requires an amount argument")
		}
		env := rs.Env()
		roundingID := rs.IDs()[0]
		amount, ok := toFloat(args[0])
		if !ok {
			return nil, fmt.Errorf("account: invalid amount for rounding")
		}

		var precision float64
		var method string
		env.Tx().QueryRow(env.Ctx(),
			`SELECT COALESCE(rounding, 0.01), COALESCE(rounding_method, 'HALF-UP')
			 FROM account_cash_rounding WHERE id = $1`, roundingID,
		).Scan(&precision, &method)

		if precision <= 0 {
			precision = 0.01
		}

		var rounded float64
		switch method {
		case "UP":
			rounded = math.Ceil(amount/precision) * precision
		case "DOWN":
			rounded = math.Floor(amount/precision) * precision
		default: // HALF-UP
			rounded = math.Round(amount/precision) * precision
		}

		// Round to avoid float precision issues
		rounded = math.Round(rounded*100) / 100
		diff := rounded - amount

		return map[string]interface{}{
			"rounded":    rounded,
			"difference": math.Round(diff*100) / 100,
		}, nil
	})
}

// initAccountInvoiceSend registers the invoice send wizard.
// Mirrors: odoo/addons/account/wizard/account_invoice_send.py
//
// This wizard handles sending invoices by email and/or generating PDF.
func initAccountInvoiceSend() {
	m := orm.NewModel("account.invoice.send", orm.ModelOpts{
		Description: "Invoice Send",
		Type:        orm.ModelTransient,
	})

	m.AddFields(
		orm.Many2many("invoice_ids", "account.move", orm.FieldOpts{
			String:   "Invoices",
			Relation: "account_invoice_send_move_rel",
			Column1:  "wizard_id",
			Column2:  "move_id",
		}),
		orm.Boolean("is_email", orm.FieldOpts{String: "Email", Default: true}),
		orm.Boolean("is_print", orm.FieldOpts{String: "Print", Default: false}),
		orm.Char("partner_ids", orm.FieldOpts{String: "Partners"}),
		orm.Many2one("template_id", "mail.template", orm.FieldOpts{String: "Email Template"}),
		orm.Many2one("composer_id", "mail.compose.message", orm.FieldOpts{String: "Composer"}),
	)

	// action_send_and_print: processes the sending/printing of invoices.
	// Mirrors: odoo/addons/account/wizard/account_invoice_send.py send_and_print_action()
	m.RegisterMethod("action_send_and_print", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		// For now, just mark invoices as sent and return close action
		env := rs.Env()
		wizID := rs.IDs()[0]

		// Get invoice IDs from the wizard
		rows, err := env.Tx().Query(env.Ctx(),
			`SELECT move_id FROM account_invoice_send_move_rel WHERE wizard_id = $1`, wizID)
		if err != nil {
			return map[string]interface{}{"type": "ir.actions.act_window_close"}, nil
		}
		defer rows.Close()

		for rows.Next() {
			var moveID int64
			if err := rows.Scan(&moveID); err != nil {
				continue
			}
			// Mark the invoice as sent (set invoice_sent flag via message)
			env.Tx().Exec(env.Ctx(),
				`UPDATE account_move SET ref = COALESCE(ref, '') || ' [Sent]' WHERE id = $1`, moveID)
		}

		return map[string]interface{}{
			"type": "ir.actions.act_window_close",
		}, nil
	})
}

// initAccountCashRoundingOnMove extends account.move with cash rounding support.
func initAccountCashRoundingOnMove() {
	ext := orm.ExtendModel("account.move")
	ext.AddFields(
		orm.Many2one("invoice_cash_rounding_id", "account.cash.rounding", orm.FieldOpts{
			String: "Cash Rounding Method",
			Help:   "Defines the smallest coinage of the currency that can be used to pay",
		}),
	)
}
