package models

import (
	"context"
	"fmt"
	"math"
	"math/rand"
	"testing"
	"time"

	"quyun/app/requests"
	"quyun/app/service/testx"
	"quyun/database"
	"quyun/database/schemas/public/model"
	"quyun/database/schemas/public/table"

	. "github.com/smartystreets/goconvey/convey"
	"go.ipao.vip/atom/contracts"

	// . "github.com/go-jet/jet/v2/postgres"
	"github.com/stretchr/testify/suite"
	"go.uber.org/dig"
)

type MediasInjectParams struct {
	dig.In
	Initials []contracts.Initial `group:"initials"`
}

type MediasTestSuite struct {
	suite.Suite

	MediasInjectParams
}

func Test_medias(t *testing.T) {
	providers := testx.Default().With(Provide)
	testx.Serve(providers, t, func(params MediasInjectParams) {
		suite.Run(t, &MediasTestSuite{MediasInjectParams: params})
	})
}

func (s *MediasTestSuite) Test_countByCondition() {
	Convey("countByCondition", s.T(), func() {
		Convey("no cond", func() {
			database.Truncate(context.Background(), db, table.Medias.TableName())

			cnt, err := Medias.countByCondition(context.Background(), nil)
			Convey("should not return an error", func() {
				So(err, ShouldBeNil)
			})
			Convey("should return a count of zero", func() {
				So(cnt, ShouldEqual, 0)
			})
		})
	})
}

func (s *MediasTestSuite) Test_BatchCreate() {
	Convey("Create", s.T(), func() {
		Convey("valid media", func() {
			database.Truncate(context.Background(), db, table.Medias.TableName())

			models := []*model.Medias{
				{
					Name:      "test 01",
					CreatedAt: time.Now(),
					MimeType:  "video/mp4",
					Size:      rand.Int63n(math.MaxInt64), // Random size
					Path:      "path/to/media.mp4",
				},
				{
					Name:      "test 02",
					CreatedAt: time.Now(),
					MimeType:  "audio/mp3",
					Size:      rand.Int63n(math.MaxInt64), // Random size
					Path:      "path/to/media.mp3",
				},
				{
					Name:      "test 03",
					CreatedAt: time.Now(),
					MimeType:  "application/pdf",
					Size:      rand.Int63n(math.MaxInt64), // Random size
					Path:      "path/to/media.pdf",
				},
				{
					Name:      "test 04",
					CreatedAt: time.Now(),
					MimeType:  "image/jpeg",
					Size:      rand.Int63n(math.MaxInt64), // Random size
					Path:      "path/to/media.jpeg",
				},
				{
					Name:      "test 05",
					CreatedAt: time.Now(),
					MimeType:  "application/zip",
					Size:      rand.Int63n(math.MaxInt64), // Random size
					Path:      "path/to/media.zip",
				},
			}

			count := 10
			for i := 0; i < count; i++ {
				err := Medias.BatchCreate(context.Background(), models)
				Convey("Create should not return an error: "+fmt.Sprintf("%d", i), func() {
					So(err, ShouldBeNil)
				})
			}
		})
	})
}

func (s *MediasTestSuite) Test_Create() {
	Convey("Create", s.T(), func() {
		Convey("valid media", func() {
			database.Truncate(context.Background(), db, table.Medias.TableName())

			model := &model.Medias{
				Name:      "test",
				CreatedAt: time.Now(),
				MimeType:  "application/pdf",
				Size:      100,
				Path:      "path/to/media.pdf",
			}

			err := Medias.Create(context.Background(), model)
			Convey("Create should not return an error", func() {
				So(err, ShouldBeNil)
			})

			cnt, err := Medias.countByCondition(context.Background(), nil)
			Convey("Count should not return an error", func() {
				So(err, ShouldBeNil)
			})
			Convey("should return a count of one", func() {
				So(cnt, ShouldEqual, 1)
			})
			Convey("should create the media successfully", func() {
				So(model.ID, ShouldNotBeEmpty)
			})
		})
	})
}

func (s *MediasTestSuite) Test_Page() {
	Convey("Create", s.T(), func() {
		Convey("Insert Items", func() {
			database.Truncate(context.Background(), db, table.Medias.TableName())

			for i := 0; i < 20; i++ {
				model := &model.Medias{
					Name:      fmt.Sprintf("test-%d", i),
					CreatedAt: time.Now(),
					MimeType:  "application/pdf",
					Size:      100,
					Path:      "path/to/media.pdf",
				}

				err := Medias.Create(context.Background(), model)
				So(err, ShouldBeNil)
			}

			cnt, err := Medias.countByCondition(context.Background(), nil)
			So(err, ShouldBeNil)
			So(cnt, ShouldEqual, 20)
		})

		Convey("Page", func() {
			Convey("page 1", func() {
				pager, err := Medias.List(context.Background(), &requests.Pagination{Page: 1, Limit: 10}, nil)
				So(err, ShouldBeNil)
				So(pager.Total, ShouldEqual, 20)
				So(pager.Items, ShouldHaveLength, 10)
			})
			Convey("page 2", func() {
				pager, err := Medias.List(context.Background(), &requests.Pagination{Page: 2, Limit: 10}, nil)
				So(err, ShouldBeNil)
				So(pager.Total, ShouldEqual, 20)
				So(pager.Items, ShouldHaveLength, 10)
			})

			Convey("page 3", func() {
				pager, err := Medias.List(context.Background(), &requests.Pagination{Page: 3, Limit: 10}, nil)
				So(err, ShouldBeNil)
				So(pager.Total, ShouldEqual, 20)
				So(pager.Items, ShouldBeEmpty)
			})
		})
	})
}

func (s *MediasTestSuite) Test_CreateGetID() {
	Convey("Create", s.T(), func() {
		model := &model.Medias{
			Name:      fmt.Sprintf("test-%d", 1),
			CreatedAt: time.Now(),
			MimeType:  "application/pdf",
			Size:      100,
			Path:      "path/to/media.pdf",
		}

		err := Medias.Create(context.Background(), model)
		So(err, ShouldBeNil)
		So(model.ID, ShouldNotBeEmpty)

		s.T().Logf("model id :%d", model.ID)
	})
}

func (s *MediasTestSuite) Test_GetRelations() {
	Convey("GetByHash", s.T(), func() {
		hash := "ce4cd071128cef282cf315dda75bdab4"
		media, err := Medias.GetRelations(context.Background(), hash)
		So(err, ShouldBeNil)
		So(media, ShouldNotBeNil)

		s.T().Logf("media: %+v", media)
	})
}
