package main

import (
	"encoding/json"
	"fmt"

	"git.tornberg.me/go-cart-actor/pkg/cart"
)

// CheckoutMeta carries the external / URL metadata required to build a
// Klarna CheckoutOrder from a CartGrain snapshot. It deliberately excludes
// any Klarna-specific response fields (HTML snippet, client token, etc.).
type CheckoutMeta struct {
	Terms        string
	Checkout     string
	Confirmation string
	Validation   string
	Push         string
	Country      string
	Currency     string // optional override (defaults to "SEK" if empty)
	Locale       string // optional override (defaults to "sv-se" if empty)
}

// BuildCheckoutOrderPayload converts the current cart grain + meta information
// into a CheckoutOrder domain struct and returns its JSON-serialized payload
// (to send to Klarna) alongside the structured CheckoutOrder object.
//
// This function is PURE: it does not perform any network I/O or mutate the
// grain. The caller is responsible for:
//
//  1. Choosing whether to create or update the Klarna order.
//  2. Invoking KlarnaClient.CreateOrder / UpdateOrder with the returned payload.
//  3. Applying an InitializeCheckout mutation (or equivalent) with the
//     resulting Klarna order id + status.
//
// If you later need to support different tax rates per line, you can extend
// CartItem / Delivery to expose that data and propagate it here.
func BuildCheckoutOrderPayload(grain *cart.CartGrain, meta *CheckoutMeta) ([]byte, *CheckoutOrder, error) {
	if grain == nil {
		return nil, nil, fmt.Errorf("nil grain")
	}
	if meta == nil {
		return nil, nil, fmt.Errorf("nil checkout meta")
	}

	currency := meta.Currency
	if currency == "" {
		currency = "SEK"
	}
	locale := meta.Locale
	if locale == "" {
		locale = "sv-se"
	}
	country := meta.Country
	if country == "" {
		country = "SE" // sensible default; adjust if multi-country support changes
	}

	lines := make([]*Line, 0, len(grain.Items)+len(grain.Deliveries))

	// Item lines
	for _, it := range grain.Items {
		if it == nil {
			continue
		}
		lines = append(lines, &Line{
			Type:           "physical",
			Reference:      it.Sku,
			Name:           it.Meta.Name,
			Quantity:       it.Quantity,
			UnitPrice:      int(it.Price.IncVat),
			TaxRate:        2500, // TODO: derive if variable tax rates are introduced
			QuantityUnit:   "st",
			TotalAmount:    int(it.TotalPrice.IncVat),
			TotalTaxAmount: int(it.TotalPrice.TotalVat()),
			ImageURL:       fmt.Sprintf("https://www.elgiganten.se%s", it.Meta.Image),
		})
	}

	// Delivery lines
	for _, d := range grain.Deliveries {
		if d == nil || d.Price.IncVat <= 0 {
			continue
		}
		lines = append(lines, &Line{
			Type:           "shipping_fee",
			Reference:      d.Provider,
			Name:           "Delivery",
			Quantity:       1,
			UnitPrice:      int(d.Price.IncVat),
			TaxRate:        2500,
			QuantityUnit:   "st",
			TotalAmount:    int(d.Price.IncVat),
			TotalTaxAmount: int(d.Price.TotalVat()),
		})
	}

	order := &CheckoutOrder{
		PurchaseCountry:    country,
		PurchaseCurrency:   currency,
		Locale:             locale,
		OrderAmount:        int(grain.TotalPrice.IncVat),
		OrderTaxAmount:     int(grain.TotalPrice.TotalVat()),
		OrderLines:         lines,
		MerchantReference1: grain.Id.String(),
		MerchantURLS: &CheckoutMerchantURLS{
			Terms:        meta.Terms,
			Checkout:     meta.Checkout,
			Confirmation: meta.Confirmation,
			Validation:   meta.Validation,
			Push:         meta.Push,
		},
	}

	payload, err := json.Marshal(order)
	if err != nil {
		return nil, nil, fmt.Errorf("marshal checkout order: %w", err)
	}

	return payload, order, nil
}
