package ana

import (
	"regexp"
	"slices"
	"strings"

	"gogs.inhome.blapointe.com/ana-ledger/src/ledger"
)

type Normalizer struct {
	m map[string][]normalize
}

type normalize struct {
	startDate string
	factor    float64
}

func NewDefaultNormalizer() Normalizer {
	return NewNormalizer().
		With("^Zach", "2026-01-01", 156). // turtle up again!
		With("^Zach", "2025-09-01", 151). // turtle up
		With("^Zach", "2023-10-05", 139). // to turtle
		With("^Zach", "2021-12-30", 135). // at pluralsight
		With("^Zach", "2020-07-30", 120). // to pluralsight
		With("^Zach", "2019-07-16", 77).  // at fedex
		With("^Zach", "2017-02-16", 49).  // to fedex
		With("^Bel", "2025-10-01", 225).  // render up
		With("^Bel", "2025-04-01", 214).  // lc4 at render
		With("^Bel", "2023-12-05", 190).  // to render
		With("^Bel", "2022-12-31", 154).  // at q
		With("^Bel", "2022-06-30", 148).  // at q
		With("^Bel", "2021-12-31", 122).  // at q
		With("^Bel", "2020-12-31", 118).  // at q
		With("^Bel", "2019-12-31", 111).  // at q
		With("^Bel", "2018-12-31", 92).   // at q
		With("^Bel", "2018-02-16", 86)    // to q
}

func NewNormalizer() Normalizer {
	return Normalizer{
		m: make(map[string][]normalize),
	}
}

func (n Normalizer) With(pattern, startDate string, factor float64) Normalizer {
	n.m[pattern] = append(n.m[pattern], normalize{startDate: startDate, factor: factor})
	slices.SortFunc(n.m[pattern], func(a, b normalize) int {
		return -1 * strings.Compare(a.startDate, b.startDate)
	})
	return n
}

func (n Normalizer) Normalize(deltas ledger.Deltas) ledger.Deltas {
	deltas = slices.Clone(deltas)

	patterns := []string{}
	for pattern := range n.m {
		patterns = append(patterns, pattern)
	}
	like := ledger.LikeName(strings.Join(patterns, "|"))

	for i, delta := range deltas {
		if !like(delta) {
			continue
		}
		deltas[i] = n.NormalizeDelta(delta)
	}

	return deltas
}

func (n Normalizer) NormalizeDelta(delta ledger.Delta) ledger.Delta {
	delta.Value /= n.NormalizeFactor(delta.Name, delta.Date)
	return delta
}

func (n Normalizer) NormalizeFactor(name, date string) float64 {
	for pattern := range n.m {
		if regexp.MustCompile(pattern).MatchString(name) {
			for _, normalize := range n.m[pattern] {
				if normalize.startDate < date {
					return normalize.factor
				}
			}
		}
	}
	return 1.0
}
