package domain

import (
	"errors"
	"fmt"
	"math"
	"time"
)

type Currency int64

// ToCurrency converts a float32 (like 12.34) into Currency (stored in cents).
func ToCurrency(f float32) Currency {
	cents := math.Round(float64(f) * 100) // avoid float32 precision issues
	return Currency(int64(cents))
}

// Float32 converts a Currency back into float32 (like 12.34).
func (m Currency) Float32() float32 {
	return float32(m) / 100
}

// String returns a formatted Currency value for display.
func (m Currency) String() string {
	return fmt.Sprintf("$%.2f", m.Float32())
}

// TODO: Change the currency to this format when implementing multi-currency
// type Currency struct {
// 	Value int64
// 	Type  IntCurrency
// }

// // ToCurrency converts a float32 (like 12.34) into Currency (stored in cents).
// func NewCurrency(f float32, currencyType IntCurrency) Currency {
// 	cents := math.Round(float64(f) * 100) // avoid float32 precision issues
// 	return Currency{
// 		Value: int64(cents),
// 		Type: currencyType,
// 	}
// }

// func NewBase(v int64) Currency {
// 	return Currency{
// 		Value: v,
// 		Type: BASE,
// 	}
// }

// // Float32 converts a Currency back into float32 (like 12.34).
// func (m Currency) Float32() float32 {
// 	return float32(m.Value) / 100
// }

// // String returns a formatted Currency value for display.
// func (m Currency) String() string {
// 	return fmt.Sprintf("$%.2f", m.Float32())
// }

type IntCurrency string

const (
	BASE IntCurrency = "BASE"
	ETB  IntCurrency = "ETB" // Ethiopian Birr
	NGN  IntCurrency = "NGN" // Nigerian Naira
	ZAR  IntCurrency = "ZAR" // South African Rand
	EGP  IntCurrency = "EGP" // Egyptian Pound
	KES  IntCurrency = "KES" // Kenyan Shilling
	UGX  IntCurrency = "UGX" // Ugandan Shilling
	TZS  IntCurrency = "TZS" // Tanzanian Shilling
	RWF  IntCurrency = "RWF" // Rwandan Franc
	BIF  IntCurrency = "BIF" // Burundian Franc
	XOF  IntCurrency = "XOF" // West African CFA Franc (BCEAO)
	XAF  IntCurrency = "XAF" // Central African CFA Franc (BEAC)
	GHS  IntCurrency = "GHS" // Ghanaian Cedi
	SDG  IntCurrency = "SDG" // Sudanese Pound
	SSP  IntCurrency = "SSP" // South Sudanese Pound
	DZD  IntCurrency = "DZD" // Algerian Dinar
	MAD  IntCurrency = "MAD" // Moroccan Dirham
	TND  IntCurrency = "TND" // Tunisian Dinar
	LYD  IntCurrency = "LYD" // Libyan Dinar
	MZN  IntCurrency = "MZN" // Mozambican Metical
	AOA  IntCurrency = "AOA" // Angolan Kwanza
	BWP  IntCurrency = "BWP" // Botswana Pula
	ZMW  IntCurrency = "ZMW" // Zambian Kwacha
	MWK  IntCurrency = "MWK" // Malawian Kwacha
	LSL  IntCurrency = "LSL" // Lesotho Loti
	NAD  IntCurrency = "NAD" // Namibian Dollar
	SZL  IntCurrency = "SZL" // Swazi Lilangeni
	CVE  IntCurrency = "CVE" // Cape Verdean Escudo
	GMD  IntCurrency = "GMD" // Gambian Dalasi
	SLL  IntCurrency = "SLL" // Sierra Leonean Leone
	LRD  IntCurrency = "LRD" // Liberian Dollar
	GNF  IntCurrency = "GNF" // Guinean Franc
	XCD  IntCurrency = "XCD" // Eastern Caribbean Dollar (used in Saint Lucia)
	MRU  IntCurrency = "MRU" // Mauritanian Ouguiya
	KMF  IntCurrency = "KMF" // Comorian Franc
	DJF  IntCurrency = "DJF" // Djiboutian Franc
	SOS  IntCurrency = "SOS" // Somali Shilling
	ERN  IntCurrency = "ERN" // Eritrean Nakfa
	MGA  IntCurrency = "MGA" // Malagasy Ariary
	SCR  IntCurrency = "SCR" // Seychellois Rupee
	MUR  IntCurrency = "MUR" // Mauritian Rupee

	// International currencies (already listed)
	USD IntCurrency = "USD" // US Dollar
	EUR IntCurrency = "EUR" // Euro
	GBP IntCurrency = "GBP" // British Pound
)

var (
	ErrUnsupportedIntCurrency = errors.New("unsupported IntCurrency")
	ErrIntCurrencyConversion  = errors.New("IntCurrency conversion failed")
)

// IntCurrencyRate represents exchange rate between two currencies
type IntCurrencyRate struct {
	From       IntCurrency
	To         IntCurrency
	Rate       float64
	ValidUntil time.Time
}

// Convert converts amount from one IntCurrency to another
func (cr IntCurrencyRate) Convert(amount float64) (float64, error) {
	if time.Now().After(cr.ValidUntil) {
		return 0, fmt.Errorf("%w: rate expired", ErrIntCurrencyConversion)
	}
	return amount * cr.Rate, nil
}

// ValidateIntCurrency checks if IntCurrency is supported
func ValidateIntCurrency(c IntCurrency) error {
	switch c {
	case ETB, USD, EUR, GBP:
		return nil
	default:
		return fmt.Errorf("%w: %s", ErrUnsupportedIntCurrency, c)
	}
}
