package main

import (
	"fmt"

	"github.com/shopspring/decimal"
)

func main() {
	// Problem with float64 for money
	f1 := 0.1
	f2 := 0.2
	fmt.Printf("Float: 0.1 + 0.2 = %.20f\n", f1+f2) // 0.30000000000000004!

	// Create decimals from various types
	d1 := decimal.NewFromFloat(0.1)
	d2 := decimal.NewFromFloat(0.2)
	sum := d1.Add(d2)
	fmt.Println("Decimal: 0.1 + 0.2 =", sum) // 0.3 (exact!)

	// Create from string (most precise)
	price := decimal.RequireFromString("19.99")
	qty := decimal.NewFromInt(3)
	total := price.Mul(qty)
	fmt.Println("Total:", total) // 59.97

	// Tax calculation with precision
	taxRate := decimal.RequireFromString("0.0825") // 8.25% tax
	subtotal := decimal.RequireFromString("100.00")
	tax := subtotal.Mul(taxRate)
	grandTotal := subtotal.Add(tax)
	fmt.Println("Subtotal:", subtotal)     // 100
	fmt.Println("Tax:", tax)               // 8.25
	fmt.Println("Grand Total:", grandTotal) // 108.25

	// Division with precision control
	a := decimal.NewFromInt(10)
	b := decimal.NewFromInt(3)
	result := a.Div(b)
	fmt.Println("10/3 =", result) // Full precision: 3.3333333333333333...

	// Round for display
	rounded := result.Round(2)
	fmt.Println("Rounded:", rounded) // 3.33

	// Different rounding modes
	val := decimal.RequireFromString("2.5")
	fmt.Println("Round:", val.Round(0))     // 3 (half away from zero)
	fmt.Println("Floor:", val.Floor())      // 2
	fmt.Println("Ceil:", val.Ceil())        // 3
	fmt.Println("Truncate:", val.Truncate(0)) // 2

	// Comparison
	p1 := decimal.RequireFromString("10.00")
	p2 := decimal.RequireFromString("10")
	fmt.Println("Equal:", p1.Equal(p2))             // true
	fmt.Println("Greater than:", p1.GreaterThan(p2)) // false

	// Check sign
	neg := decimal.NewFromInt(-5)
	fmt.Println("Is negative:", neg.IsNegative()) // true
	fmt.Println("Is positive:", neg.IsPositive()) // false
	fmt.Println("Is zero:", neg.IsZero())         // false
	fmt.Println("Absolute:", neg.Abs())           // 5

	// String formatting
	amount := decimal.RequireFromString("1234.5")
	fmt.Println("String:", amount.String())            // 1234.5
	fmt.Println("Fixed 2:", amount.StringFixed(2))     // 1234.50
	fmt.Println("Fixed 4:", amount.StringFixed(4))     // 1234.5000

	// Convert to float (when needed for external APIs)
	f, exact := amount.Float64()
	fmt.Printf("Float64: %v (exact: %v)\n", f, exact)
}
