// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// operand-fraction.go
package expr

//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html

import (
	"fmt"

	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/expr/scan"
	"git.portale-stac.it/go-pkg/expr/sym"
	"git.portale-stac.it/go-pkg/expr/types/fract"
)

// -------- fraction term
func newFractionTerm(tk *scan.Token) *scan.Term {
	return &scan.Term{
		Tk:       *tk,
		Children: make([]*scan.Term, 0, 2),
		Position: scan.PosInfix,
		Priority: scan.PriFraction,
		EvalFunc: evalFraction,
	}
}

// -------- eval func
func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
	var numValue, denValue any
	var num, den int64
	var ok bool

	if numValue, denValue, err = opTerm.EvalInfix(ctx); err != nil {
		return
	}
	if num, ok = numValue.(int64); !ok {
		err = fmt.Errorf("numerator must be integer, got %T (%v)", numValue, numValue)
		return
	}
	if den, ok = denValue.(int64); !ok {
		err = fmt.Errorf("denominator must be integer, got %T (%v)", denValue, denValue)
		return
	}
	if den == 0 {
		err = opTerm.Errorf("division by zero")
		return
	}

	if den < 0 {
		den = -den
		num = -num
	}
	if num != 0 {
		if g := fract.Gcd(num, den); g != 1 {
			num = num / g
			den = den / g
		}
		if den == 1 {
			v = num
		} else {
			// v = &expr.FractionType{num, den}
			v = fract.NewFraction(num, den)
		}
	} else {
		// v = &FractionType{0, den}
		v = fract.NewFraction(0, den)
	}
	return
}

// init
func init() {
	// registerTermConstructor(SymVertBar, newFractionTerm)
	scan.RegisterTermConstructor(sym.SymColon, newFractionTerm)
}
