package find

import (
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type sqlCalcFound struct{}

// Creates a new Clause which adds `SQL_CALC_FOUND_ROWS` right after `SELECT`.
// If [find.FoundRowsCallback] is registered the presence of this clause will
// cause `FOUND_ROWS()` result to be available in the driver context.
func SqlCalcFound() sqlCalcFound {
	return sqlCalcFound{}
}

// Implements gorm's [clause.Clause]
func (sqlCalcFound) Name() string {
	return "SQL_CALC_FOUND_ROWS"
}

// Implements gorm's [clause.Clause]
func (sqlCalcFound) Build(builder clause.Builder) {
	_, _ = builder.WriteString("SQL_CALC_FOUND_ROWS")
}

// Implements gorm's [clause.Clause]
func (sqlCalcFound) MergeClause(cl *clause.Clause) {
}

// Implements [gorm.StatementModifier]
func (calc sqlCalcFound) ModifyStatement(stmt *gorm.Statement) {
	selectClause := stmt.Clauses["SELECT"]
	if selectClause.AfterNameExpression == nil {
		selectClause.AfterNameExpression = calc
	} else if _, ok := selectClause.AfterNameExpression.(sqlCalcFound); !ok {
		selectClause.AfterNameExpression = exprs{selectClause.AfterNameExpression, calc}
	}
	stmt.Clauses["SELECT"] = selectClause
}

type exprs []clause.Expression

func (exprs exprs) Build(builder clause.Builder) {
	for idx, expr := range exprs {
		if idx > 0 {
			_ = builder.WriteByte(' ')
		}
		expr.Build(builder)
	}
}
