// Copyright 2017 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tests

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestSum(t *testing.T) {
	type SumStruct struct {
		Int   int
		Float float32
	}

	assert.NoError(t, PrepareEngine())
	assert.NoError(t, testEngine.Sync(new(SumStruct)))

	cases := []SumStruct{
		{1, 6.2},
		{2, 5.3},
		{92, -0.2},
	}

	var i int
	var f float32
	for _, v := range cases {
		i += v.Int
		f += v.Float
	}

	cnt, err := testEngine.Insert(cases)
	assert.NoError(t, err)
	assert.EqualValues(t, 3, cnt)

	colInt := testEngine.GetColumnMapper().Obj2Table("Int")
	colFloat := testEngine.GetColumnMapper().Obj2Table("Float")

	sumInt, err := testEngine.Sum(new(SumStruct), colInt)
	assert.NoError(t, err)
	assert.EqualValues(t, int(sumInt), i)

	sumFloat, err := testEngine.Sum(new(SumStruct), colFloat)
	assert.NoError(t, err)
	assert.InEpsilon(t, sumFloat, f, 0.01)

	sums, err := testEngine.Sums(new(SumStruct), colInt, colFloat)
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(sums))
	assert.EqualValues(t, i, int(sums[0]))
	assert.InEpsilon(t, f, sums[1], 0.01)

	sumsInt, err := testEngine.SumsInt(new(SumStruct), colInt)
	assert.NoError(t, err)
	assert.EqualValues(t, 1, len(sumsInt))
	assert.EqualValues(t, i, int(sumsInt[0]))
}

type SumStructWithTableName struct {
	Int   int
	Float float32
}

func (s SumStructWithTableName) TableName() string {
	return "sum_struct_with_table_name_1"
}

func TestSumWithTableName(t *testing.T) {
	assert.NoError(t, PrepareEngine())
	assert.NoError(t, testEngine.Sync(new(SumStructWithTableName)))

	cases := []SumStructWithTableName{
		{1, 6.2},
		{2, 5.3},
		{92, -0.2},
	}

	var i int
	var f float32
	for _, v := range cases {
		i += v.Int
		f += v.Float
	}

	cnt, err := testEngine.Insert(cases)
	assert.NoError(t, err)
	assert.EqualValues(t, 3, cnt)

	colInt := testEngine.GetColumnMapper().Obj2Table("Int")
	colFloat := testEngine.GetColumnMapper().Obj2Table("Float")

	sumInt, err := testEngine.Sum(new(SumStructWithTableName), colInt)
	assert.NoError(t, err)
	assert.EqualValues(t, int(sumInt), i)

	sumFloat, err := testEngine.Sum(new(SumStructWithTableName), colFloat)
	assert.NoError(t, err)
	assert.InEpsilon(t, f, sumFloat, 0.01)

	sums, err := testEngine.Sums(new(SumStructWithTableName), colInt, colFloat)
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(sums))
	assert.EqualValues(t, i, int(sums[0]))
	assert.InEpsilon(t, f, sums[1], 0.01)

	sumsInt, err := testEngine.SumsInt(new(SumStructWithTableName), colInt)
	assert.NoError(t, err)
	assert.EqualValues(t, 1, len(sumsInt))
	assert.EqualValues(t, i, int(sumsInt[0]))
}

func TestSumCustomColumn(t *testing.T) {
	assert.NoError(t, PrepareEngine())

	type SumStruct2 struct {
		Int   int
		Float float32
	}

	cases := []SumStruct2{
		{1, 6.2},
		{2, 5.3},
		{92, -0.2},
	}

	assert.NoError(t, testEngine.Sync(new(SumStruct2)))

	cnt, err := testEngine.Insert(cases)
	assert.NoError(t, err)
	assert.EqualValues(t, 3, cnt)

	sumInt, err := testEngine.Sum(new(SumStruct2),
		"CASE WHEN `int` <= 2 THEN `int` ELSE 0 END")
	assert.NoError(t, err)
	assert.EqualValues(t, 3, int(sumInt))
}
