package cvt

import (
	"testing"
	"time"

	maintent "github.com/tidbcloud/devops/entity/maintenance"

	"github.com/tidbcloud/devops/models/base"
	maintmod "github.com/tidbcloud/devops/models/maintenance"
	"github.com/tidbcloud/devops/pkg/infra/utils/test"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

func TestRepo(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "ClusterMaintenance Converter Suite")
}

var _ = Describe("[ClusterMaintenance Converter]", func() {

	Describe("[ClusterMaintenance]", func() {
		Describe("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				time := time.Now()

				// every fields MUST be set as a non zero value
				org := &maintmod.ClusterMaintenance{
					Updatable: base.Updatable{
						Base:      base.Base{ID: base.ID(1), CreatedAt: time},
						UpdatedAt: &time,
					},

					LarkNotifiedAt:           &time,
					InstanceID:               102,
					LastNotifiedCustomerDate: &time,
					ScheduledApplyTime:       &time,
				}
				exp := &maintent.ClusterMaintenanceInRepo{
					ID:                       1,
					LarkNotifiedAt:           &time,
					InstanceID:               102,
					LastNotifiedCustomerDate: &time,
					ScheduledApplyTime:       &time,
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.ClusterMaintenance(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})

		})

		Describe("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				time := time.Now()

				// every fields MUST be set as a non zero value
				org := &maintent.ClusterMaintenanceInRepo{
					ID:                       1,
					LarkNotifiedAt:           &time,
					InstanceID:               102,
					LastNotifiedCustomerDate: &time,
					ScheduledApplyTime:       &time,
				}
				exp := &maintmod.ClusterMaintenance{
					Updatable: base.Updatable{
						Base: base.Base{ID: base.ID(1)},
					},
					LarkNotifiedAt:           &time,
					InstanceID:               102,
					LastNotifiedCustomerDate: &time,
					ScheduledApplyTime:       &time,
				}
				ignoredFields := []string{
					".Updatable.Base.CreatedAt",
					".Updatable.UpdatedAt",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.ClusterMaintenance(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})
	})

	Describe("[ClusterOpsMaintenanceWindow]", func() {
		Describe("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				now := time.Now()

				org := &maintmod.ClusterOpsMaintenanceWindow{
					Updatable: base.Updatable{
						Base:      base.Base{ID: base.ID(1), CreatedAt: now},
						UpdatedAt: &now,
					},
					ClusterID: "101",
					Windows:   []byte(`[{"start_cron_spec":"3 2 * * 1","duration":"1d","description":"weekly window"}]`),
					Approvers: "approver_1@pingcap.com, approver_2@pingcap.com,,",
				}

				exp := &maintent.ClusterOpsMaintenanceWindow{
					ID:        1,
					ClusterID: "101",
					Windows: []maintent.ClusterOpsMaintenanceWindowSlot{
						{
							StartCronSpec: "3 2 * * 1",
							Duration:      "1d",
							Description:   "weekly window",
						},
					},
					Approvers: []string{"approver_1@pingcap.com", "approver_2@pingcap.com"},
					CreatedAt: now,
					UpdatedAt: &now,
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil())
				got := m2e{}.ClusterOpsMaintenanceWindow(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil())
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

		Describe("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				now := time.Now()

				org := &maintent.ClusterOpsMaintenanceWindow{
					ID:        1,
					ClusterID: "101",
					Windows: []maintent.ClusterOpsMaintenanceWindowSlot{
						{
							StartCronSpec: "3 2 * * 1",
							Duration:      "1d",
							Description:   "weekly window",
						},
					},
					Approvers: []string{"approver_1@pingcap.com", "approver_2@pingcap.com"},
					CreatedAt: now,
					UpdatedAt: &now,
				}

				exp := &maintmod.ClusterOpsMaintenanceWindow{
					Updatable: base.Updatable{
						Base: base.Base{ID: base.ID(1)},
					},
					ClusterID: "101",
					Windows:   []byte(`[{"start_cron_spec":"3 2 * * 1","duration":"1d","description":"weekly window"}]`),
					Approvers: "approver_1@pingcap.com,approver_2@pingcap.com",
				}
				ignoredFields := []string{
					".Updatable.Base.CreatedAt",
					".Updatable.UpdatedAt",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil())
				got := e2m{}.ClusterOpsMaintenanceWindow(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil())
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})

			It("should convert empty approvers string to empty slice", func() {
				org := &maintmod.ClusterOpsMaintenanceWindow{
					ClusterID: "101",
					Windows:   []byte(`[]`),
					Approvers: "",
				}

				got := m2e{}.ClusterOpsMaintenanceWindow(org)
				Expect(got.Approvers).To(Equal([]string{}))
			})
		})
	})

	Describe("[OpsExecutionWindow]", func() {
		Describe("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				now := time.Now()
				startAt := now.Add(time.Hour)
				endAt := now.Add(2 * time.Hour)

				org := &maintmod.OpsExecutionWindow{
					Updatable: base.Updatable{
						Base:      base.Base{ID: base.ID(1), CreatedAt: now},
						UpdatedAt: &now,
					},
					StartAt: startAt,
					EndAt:   endAt,
				}

				exp := &maintent.OpsExecutionWindow{
					ID:        1,
					CreatedAt: now.Unix(),
					UpdatedAt: now.Unix(),
					StartAt:   startAt.Unix(),
					EndAt:     endAt.Unix(),
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil())
				got := m2e{}.OpsExecutionWindow(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil())
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

		Describe("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				now := time.Now()
				startAt := now.Add(time.Hour)
				endAt := now.Add(2 * time.Hour)

				org := &maintent.OpsExecutionWindow{
					ID:        1,
					CreatedAt: now.Unix(),
					UpdatedAt: now.Unix(),
					StartAt:   startAt.Unix(),
					EndAt:     endAt.Unix(),
				}

				exp := &maintmod.OpsExecutionWindow{
					Updatable: base.Updatable{
						Base: base.Base{ID: base.ID(1)},
					},
					StartAt: time.Unix(startAt.Unix(), 0),
					EndAt:   time.Unix(endAt.Unix(), 0),
				}
				ignoredFields := []string{
					".Updatable.Base.CreatedAt",
					".Updatable.UpdatedAt",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil())
				got := e2m{}.OpsExecutionWindow(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil())
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})
	})

})
