package builderimp

import (
	"github.com/tech/sendico/pkg/db/repository/builder"
	"go.mongodb.org/mongo-driver/v2/bson"
)

type literalAccumulatorImp struct {
	op    builder.MongoOperation
	value any
}

func (a *literalAccumulatorImp) Build() bson.D {
	return bson.D{{Key: string(a.op), Value: a.value}}
}

func NewAccumulator(op builder.MongoOperation, value any) builder.Accumulator {
	return &literalAccumulatorImp{op: op, value: value}
}

func AddToSet(value builder.Expression) builder.Expression {
	return newUnaryExpression(builder.AddToSet, value)
}

func Size(value builder.Expression) builder.Expression {
	return newUnaryExpression(builder.Size, value)
}

func Ne(left, right builder.Expression) builder.Expression {
	return newBinaryExpression(builder.Ne, left, right)
}

func Sum(value any) builder.Accumulator {
	return NewAccumulator(builder.Sum, value)
}

func Avg(value any) builder.Accumulator {
	return NewAccumulator(builder.Avg, value)
}

func Min(value any) builder.Accumulator {
	return NewAccumulator(builder.Min, value)
}

func Max(value any) builder.Accumulator {
	return NewAccumulator(builder.Max, value)
}

func Eq(left, right builder.Expression) builder.Expression {
	return newBinaryExpression(builder.Eq, left, right)
}

func Gt(left, right builder.Expression) builder.Expression {
	return newBinaryExpression(builder.Gt, left, right)
}

func Add(left, right builder.Accumulator) builder.Accumulator {
	return newBinaryAccumulator(builder.Add, left, right)
}

func Subtract(left, right builder.Accumulator) builder.Accumulator {
	return newBinaryAccumulator(builder.Subtract, left, right)
}

func Multiply(left, right builder.Accumulator) builder.Accumulator {
	return newBinaryAccumulator(builder.Multiply, left, right)
}

func Divide(left, right builder.Accumulator) builder.Accumulator {
	return newBinaryAccumulator(builder.Divide, left, right)
}

type binaryAccumulator struct {
	op    builder.MongoOperation
	left  builder.Accumulator
	right builder.Accumulator
}

func newBinaryAccumulator(op builder.MongoOperation, left, right builder.Accumulator) builder.Accumulator {
	return &binaryAccumulator{
		op:    op,
		left:  left,
		right: right,
	}
}

func (b *binaryAccumulator) Build() bson.D {
	args := []any{b.left.Build(), b.right.Build()}
	return bson.D{{Key: string(b.op), Value: args}}
}
