package model

import (
	"fmt"
	"testing"
	"time"

	"github.com/onsi/gomega"
	"github.com/pingcap/errors"
	"gorm.io/gorm"

	"github.com/pingcap-inc/clinic/pkg/db"
)

func Test_CreateOrganization(t *testing.T) {
	name := "Test_CreateOrganization"

	g := gomega.NewWithT(t)

	_, err := CreateOrganization(name, name, 1, func(orgID uint) error {
		return errors.New("test")
	})
	g.Expect(err).To(gomega.MatchError("test"))
	// cond := &ListOrganizationsCondition{
	// 	Name:    name,
	// 	Page:    -1,
	// 	PerPage: -1,
	// }
	// orgs, total, err := ListOrganizations(cond)
	// g.Expect(err).To(gomega.Succeed())
	// g.Expect(total).To(gomega.Equal(int64(0)))
	// g.Expect(len(orgs)).To(gomega.Equal(0))

	var expecteOrgID uint
	org, err := CreateOrganization(name, name, 1, func(orgID uint) error {
		expecteOrgID = orgID
		return nil
	})
	g.Expect(err).To(gomega.Succeed())
	g.Expect(expecteOrgID).To(gomega.Equal(org.ID))

	// org, err = GetOrganization(expecteOrgID)
	// g.Expect(err).To(gomega.Succeed())
	// g.Expect(org.Name).To(gomega.Equal(name))
}

func Test_GetOrganizationCount(t *testing.T) {
	prefix := "Test_GetOrganizationCount"
	userID := uint(21)

	g := gomega.NewGomegaWithT(t)

	for i := 1; i <= 11; i++ {
		_, err := CreateOrganization(fmt.Sprintf("%s%d", prefix, i), prefix, userID, func(orgID uint) error {
			return nil
		})
		g.Expect(err).To(gomega.Succeed())
	}

	count, err := GetOrganizationCount(userID)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(count).To(gomega.Equal(int64(11)))
}

func TestListCloudOrganizationUpdatedAt(t *testing.T) {
	g := gomega.NewWithT(t)
	const baseID uint = 4_000_000_000
	firstUpdatedAt := time.Date(2026, time.August, 25, 1, 0, 0, 0, time.UTC)
	secondUpdatedAt := firstUpdatedAt.Add(time.Hour)

	organizations := []db.Organization{
		{
			Model:      gorm.Model{UpdatedAt: firstUpdatedAt},
			Name:       fmt.Sprintf("sync-state-first-%d", baseID),
			DbaasOrgID: baseID,
			OrgType:    "cloud",
		},
		{
			Model:      gorm.Model{UpdatedAt: secondUpdatedAt},
			Name:       fmt.Sprintf("sync-state-second-%d", baseID),
			DbaasOrgID: baseID,
			OrgType:    "cloud",
		},
		{
			Model:      gorm.Model{UpdatedAt: secondUpdatedAt},
			Name:       fmt.Sprintf("sync-state-deleted-%d", baseID),
			DbaasOrgID: baseID + 1,
			OrgType:    "cloud",
		},
	}

	g.Expect(db.GetDB().Create(&organizations).Error).To(gomega.Succeed())
	t.Cleanup(func() {
		for i := range organizations {
			_ = db.GetDB().Unscoped().Delete(&organizations[i]).Error
		}
	})
	g.Expect(db.GetDB().Delete(&organizations[2]).Error).To(gomega.Succeed())

	updatedAtByOrgID, err := ListCloudOrganizationUpdatedAt([]uint{baseID, baseID + 1, baseID + 2})

	g.Expect(err).To(gomega.Succeed())
	g.Expect(updatedAtByOrgID).To(gomega.HaveLen(2))
	g.Expect(updatedAtByOrgID[baseID].Equal(firstUpdatedAt)).To(gomega.BeTrue())
	g.Expect(updatedAtByOrgID[baseID+1].Equal(secondUpdatedAt)).To(gomega.BeTrue())
}

// func Test_ListOrganization(t *testing.T) {
// 	prefix := "Test_ListOrganization"
// 	userID := uint(21)

// 	g := gomega.NewGomegaWithT(t)

// 	for i := 1; i <= 33; i++ {
// 		_, err := CreateOrganization(fmt.Sprintf("%s%d", prefix, i), prefix, userID, func(orgID uint) error {
// 			return nil
// 		})
// 		g.Expect(err).To(gomega.Succeed())
// 	}
// 	// set some soft deleted records
// 	g.Expect(softDeleteOrg(1)).To(gomega.Succeed())
// 	cond := &ListOrganizationsCondition{
// 		Name:    "ListOrganization",
// 		Page:    1,
// 		PerPage: 9,
// 	}
// 	orgs, total, err := ListOrganizations(cond)
// 	g.Expect(err).To(gomega.Succeed())
// 	g.Expect(total).To(gomega.Equal(int64(32)))
// 	g.Expect(len(orgs)).To(gomega.Equal(9))

// 	stream.OfSlice(orgs).Each(func(org db.Organization) {
// 		g.Expect(org.Name).To(gomega.ContainSubstring("ListOrganization"))
// 	})
// }

// func Test_FilterOrganization(t *testing.T) {
// 	prefix := "Test_FilterOrganization"
// 	userID := uint(21)

// 	g := gomega.NewGomegaWithT(t)
// 	orgIDs := make([]uint, 0, 33)
// 	for i := 1; i <= 33; i++ {
// 		_, err := CreateOrganization(fmt.Sprintf("%s%d", prefix, i), prefix, userID, func(orgID uint) error {
// 			orgIDs = append(orgIDs, orgID)
// 			return nil
// 		})
// 		g.Expect(err).To(gomega.Succeed())
// 	}
// 	err := CreateStar(context.Background(), userID, orgIDs[0])
// 	g.Expect(err).To(gomega.Succeed())
// 	err = CreateStar(context.Background(), userID, orgIDs[1])
// 	g.Expect(err).To(gomega.Succeed())
// 	err = CreateStar(context.Background(), userID, orgIDs[len(orgIDs)-1])
// 	g.Expect(err).To(gomega.Succeed())
// 	err = softDeleteOrg(orgIDs[15])
// 	{
// 		// check filter by star
// 		cond := &ListOrganizationsCondition{
// 			Name:    "FilterOrganization",
// 			StarBy:  userID,
// 			Page:    1,
// 			PerPage: 9,
// 		}
// 		orgs, total, err := ListOrganizations(cond)
// 		g.Expect(err).To(gomega.Succeed())
// 		g.Expect(total).To(gomega.Equal(int64(3)))
// 		g.Expect(len(orgs)).To(gomega.Equal(3))
// 		g.Expect(orgs[0].ID).To(gomega.Equal(orgIDs[len(orgIDs)-1]))
// 		g.Expect(orgs[1].ID).To(gomega.Equal(orgIDs[1]))
// 		g.Expect(orgs[2].ID).To(gomega.Equal(orgIDs[0]))
// 		stream.OfSlice(orgs).Each(func(org db.Organization) {
// 			g.Expect(org.Name).To(gomega.ContainSubstring("FilterOrganization"))
// 		})
// 	}
// 	{
// 		// check isStarByViewer is correctly set
// 		cond := &ListOrganizationsCondition{
// 			Page:    1,
// 			PerPage: 9,
// 			ViewBy:  userID,
// 		}
// 		orgs, total, err := ListOrganizations(cond)
// 		g.Expect(err).To(gomega.Succeed())
// 		g.Expect(total).To(gomega.Equal(int64(32)))
// 		g.Expect(len(orgs)).To(gomega.Equal(9))
// 		stream.OfSlice(orgs).Each(func(org db.Organization) {
// 			g.Expect(org.Name).To(gomega.ContainSubstring("FilterOrganization"))
// 			if org.ID == orgIDs[len(orgIDs)-1] {
// 				g.Expect(org.IsStarredByViewer()).To(gomega.BeTrue())
// 			} else {
// 				g.Expect(org.IsStarredByViewer()).To(gomega.BeFalse())
// 			}
// 		})
// 	}
// 	{
// 		// check filter by owner
// 		cond := &ListOrganizationsCondition{
// 			Name:    "FilterOrganization",
// 			Owner:   userID,
// 			Page:    1,
// 			PerPage: 9,
// 		}
// 		orgs, total, err := ListOrganizations(cond)
// 		g.Expect(err).To(gomega.Succeed())
// 		g.Expect(total).To(gomega.Equal(int64(32)))
// 		g.Expect(len(orgs)).To(gomega.Equal(9))

// 		stream.OfSlice(orgs).Each(func(org db.Organization) {
// 			g.Expect(org.Name).To(gomega.ContainSubstring("FilterOrganization"))
// 		})
// 	}
// 	// modify star record
// 	err = DeleteStar(context.Background(), userID, orgIDs[1])
// 	g.Expect(err).To(gomega.Succeed())
// 	{
// 		// check filter by star
// 		cond := &ListOrganizationsCondition{
// 			Name:    "FilterOrganization",
// 			StarBy:  userID,
// 			Page:    1,
// 			PerPage: 9,
// 		}
// 		orgs, total, err := ListOrganizations(cond)
// 		g.Expect(err).To(gomega.Succeed())
// 		g.Expect(total).To(gomega.Equal(int64(2)))
// 		g.Expect(len(orgs)).To(gomega.Equal(2))
// 		g.Expect(orgs[0].ID).To(gomega.Equal(orgIDs[len(orgIDs)-1]))
// 		stream.OfSlice(orgs).Each(func(org db.Organization) {
// 			g.Expect(org.Name).To(gomega.ContainSubstring("FilterOrganization"))
// 		})
// 	}
// }

func softDeleteOrg(orgID uint) error {
	return db.Transaction(func(tx *gorm.DB) error {
		return tx.Delete(&db.Organization{}, orgID).Error
	})
}
