package domain_test

import (
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
	"github.com/tidbcloud/dataflow-service/app/models/domain"
	"github.com/tidbcloud/dataflow-service/app/repo"
	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	"gorm.io/gorm"
)

func TestImportDomainTestSuite(t *testing.T) {
	suite.Run(t, new(importDomainTestSuite))
}

type importDomainTestSuite struct {
	suite.Suite
	db *gorm.DB
}

func (s *importDomainTestSuite) SetupSuite() {
	entity.NewDataflowEventHookerManager()
	testDB, err := repo.GetFakeDB()
	s.Require().NoError(err)
	s.db = testDB
}

//nolint:funlen
func (s *importDomainTestSuite) TestReq2ImportFilterOps() {
	testCases := []struct {
		CaseName            string
		Req                 *domain.ListImportsReq
		ExpectListQuerySet  entity.ImportQuerySet
		ExpectCountQuerySet entity.ImportQuerySet
	}{
		{
			CaseName:            "fetch all",
			Req:                 &domain.ListImportsReq{},
			ExpectListQuerySet:  entity.NewImportQuerySet(s.db).OrderDescByCreatedAt(),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db),
		},
		{
			CaseName: "by cluster id",
			Req: &domain.ListImportsReq{
				ClusterID: 123,
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				OrderDescByCreatedAt(),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123),
		},
		{
			CaseName: "by cluster id with pager",
			Req: &domain.ListImportsReq{
				ClusterID: 123,
				Page:      2,
				PerPage:   10,
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				OrderDescByCreatedAt().
				Offset(10).
				Limit(10),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123),
		},
		{
			CaseName: "by statuses",
			Req: &domain.ListImportsReq{
				Statuses: []entity.ImportStatus{
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				},
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				).
				OrderDescByCreatedAt(),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				),
		},
		{
			CaseName: "by statuses with pager",
			Req: &domain.ListImportsReq{
				Statuses: []entity.ImportStatus{
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				},
				Page:    2,
				PerPage: 10,
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				).
				OrderDescByCreatedAt().
				Offset(10).
				Limit(10),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				),
		},
		{
			CaseName: "by cluster id and statuses",
			Req: &domain.ListImportsReq{
				ClusterID: 123,
				Statuses: []entity.ImportStatus{
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				},
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				).
				OrderDescByCreatedAt(),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				),
		},
		{
			CaseName: "by cluster id and statuses with pager",
			Req: &domain.ListImportsReq{
				ClusterID: 123,
				Statuses: []entity.ImportStatus{
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				},
				Page:    2,
				PerPage: 10,
			},
			ExpectListQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				).
				OrderDescByCreatedAt().
				Offset(10).
				Limit(10),
			ExpectCountQuerySet: entity.NewImportQuerySet(s.db).
				ClusterIDEq(123).
				StatusIn(
					entity.ImportStatusCompleted,
					entity.ImportStatusFailed,
				),
		},
	}
	for _, tc := range testCases {
		s.T().Run(tc.CaseName, func(t *testing.T) {
			filterOps := tc.Req.FilterOpsForList()
			qs := entity.NewImportQuerySet(s.db)
			for _, filterOp := range filterOps {
				filterOp(qs)
			}
			require.Equal(t, tc.ExpectListQuerySet, qs)

			filterOps = tc.Req.FilterOpsForCount()
			qs = entity.NewImportQuerySet(s.db)
			for _, filterOp := range filterOps {
				filterOp(qs)
			}
			require.Equal(t, tc.ExpectCountQuerySet, qs)
		})
	}
}
