package qslcard

import (
	"sync"

	"hamlog/internal/applog"
)

// CountryInfo resolves the "auto" country element: a display label and the
// ISO code of the embedded flag ("" = no flag available).
type CountryInfo struct {
	Label   string `json:"label"`
	FlagISO string `json:"flag_iso"`
}

// RenderModel is a template with every placeholder filled, ready for the
// frontend to instantiate as SVG (editor preview and final rasterization use
// the same model so output cannot drift from preview).
type RenderModel struct {
	Template  Template          `json:"template"`
	QSOFields map[string]string `json:"qso_fields"` // values for qso_box.fields
}

// warnedPlaceholders dedupes the "unknown placeholder" log line so a bulk
// render doesn't flood the log.
var warnedPlaceholders sync.Map

// Resolve substitutes {profile.*} and {qso.*} placeholders from vars (keys
// are the full "namespace.key" form) and resolves the country element. An
// unknown placeholder resolves to "" and is logged once.
func Resolve(t Template, vars map[string]string, country CountryInfo) RenderModel {
	resolve := func(text string) string {
		return placeholderRe.ReplaceAllStringFunc(text, func(m string) string {
			key := m[1 : len(m)-1] // strip braces → "namespace.key"
			if v, ok := vars[key]; ok {
				return v
			}
			if _, seen := warnedPlaceholders.LoadOrStore(key, true); !seen {
				applog.Printf("qslcard: unknown placeholder %q resolves to empty", m)
			}
			return ""
		})
	}

	out := t
	out.Elements = make([]Element, len(t.Elements))
	copy(out.Elements, t.Elements)
	for i := range out.Elements {
		e := &out.Elements[i]
		switch e.Type {
		case ElemCallsign, ElemOperator, ElemInfoLine:
			e.Text = resolve(e.Text)
		case ElemCountry:
			if e.Flag == "auto" {
				e.Flag = country.FlagISO
			}
			if e.Label == "auto" {
				e.Label = country.Label
			}
		}
	}
	if t.QSOBox != nil {
		box := *t.QSOBox
		box.Title = resolve(box.Title)
		box.Footer = resolve(box.Footer)
		out.QSOBox = &box
	}

	model := RenderModel{Template: out, QSOFields: map[string]string{}}
	if out.QSOBox != nil {
		for _, f := range out.QSOBox.Fields {
			model.QSOFields[f] = vars["qso."+f]
		}
	}
	return model
}
