// Copyright 2025 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package placement

import (
	"testing"

	. "github.com/onsi/gomega"
)

func TestKeyspaceTxnRange(t *testing.T) {
	g := NewGomegaWithT(t)
	var err error
	g.Expect(err).NotTo(HaveOccurred())
	startKey, endKey := KeyspaceTxnRange(1)
	g.Expect(startKey).To(Equal("7800000100000000FB"))
	g.Expect(endKey).To(Equal("7800000200000000FB"))
}

func TestKeyspaceTableTxnRange(t *testing.T) {
	g := NewGomegaWithT(t)
	var err error
	g.Expect(err).NotTo(HaveOccurred())
	startKey, endKey := KeyspaceTableTxnRange(1, 2)
	g.Expect(startKey).To(Equal("7800000174800000FF0000000002000000FC"))
	g.Expect(endKey).To(Equal("7800000174800000FF0000000003000000FC"))
}

func TestFormatAndParseKeyspaceID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	key := FormatKeyspaceID(keyspaceID)
	id, err := ParseKeyspaceID(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(id).To(Equal(keyspaceID))
}

func TestFormatAndParseKeyspaceRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	key := FormatKeyspaceRuleID(keyspaceID)
	leftover, id, err := ParseKeyspaceRuleID(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(id).To(Equal(keyspaceID))
	g.Expect(leftover).To(Equal(""))
}

func TestFormatAndParseTableRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	tableID := uint64(1)
	key := FormatTableRuleID(tableID)
	leftover, id, err := ParseTableRuleID(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(id).To(Equal(tableID))
	g.Expect(leftover).To(Equal(""))
}

func TestFormatAndParseRegionRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	regionID := uint64(1)
	key := FormatRegionRuleID(regionID)
	leftover, id, err := ParseRegionRuleID(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(id).To(Equal(regionID))
	g.Expect(leftover).To(Equal(""))
}

func TestFormatAndParseKeyspaceTableRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	tableID := uint64(2)
	key := FormatKeyspaceTableRuleID(keyspaceID, tableID)
	leftover, keyspace, table, err := ParseKeyspaceTableRuleID(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(keyspace).To(Equal(keyspaceID))
	g.Expect(table).To(Equal(tableID))
	g.Expect(leftover).To(Equal(""))
}

func TestFormatAndParseKeyspaceZoneRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	{
		key := FormatKeyspaceZoneRuleID(keyspaceID, PrimaryZone)
		keyspace, zoneType, err := ParseKeyspaceZoneRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(zoneType).To(Equal(PrimaryZone))
	}
	{
		key := FormatKeyspaceZoneRuleID(keyspaceID, "")
		keyspace, zoneType, err := ParseKeyspaceZoneRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(zoneType).To(Equal(""))
	}
}

func TestFormatAndParseMultiAZKeyspaceRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	{
		key := FormatMultiAZKeyspaceRuleID(keyspaceID, PrimaryZone)
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZKeyspaceRuleID(key)).To(Equal(true))
		keyspace, zoneType, err := ParseMultiAZKeyspaceRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(zoneType).To(Equal(PrimaryZone))
	}
	{
		key := FormatMultiAZKeyspaceRuleID(keyspaceID, "")
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZKeyspaceRuleID(key)).To(Equal(true))
		keyspace, zoneType, err := ParseMultiAZKeyspaceRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(zoneType).To(Equal(""))
	}
}

func TestFormatAndParseSingleAZKeyspaceRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	{
		key := FormatSingleAZKeyspaceRuleID(keyspaceID, "leader")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZKeyspaceRuleID(key)).To(Equal(true))
		keyspace, roleType, err := ParseSingleAZKeyspaceRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(roleType).To(Equal("leader"))
	}
	{
		key := FormatSingleAZKeyspaceRuleID(keyspaceID, "")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZKeyspaceRuleID(key)).To(Equal(true))
		keyspace, roleType, err := ParseSingleAZKeyspaceRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(roleType).To(Equal(""))
	}
}

func TestFormatAndParseMultiAZKeyspaceTableRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	tableID := uint64(2)
	{
		key := FormatMultiAZKeyspaceTableRuleID(keyspaceID, tableID, PrimaryZone)
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZKeyspaceTableRuleID(key)).To(Equal(true))
		keyspace, table, zoneType, err := ParseMultiAZKeyspaceTableRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(table).To(Equal(tableID))
		g.Expect(zoneType).To(Equal(PrimaryZone))
	}
	{
		key := FormatMultiAZKeyspaceTableRuleID(keyspaceID, tableID, "")
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZKeyspaceTableRuleID(key)).To(Equal(true))
		keyspace, table, zoneType, err := ParseMultiAZKeyspaceTableRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(table).To(Equal(tableID))
		g.Expect(zoneType).To(Equal(""))
	}
}

func TestFormatAndParseSingleAZKeyspaceTableRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	keyspaceID := uint32(1)
	tableID := uint64(2)
	{
		key := FormatSingleAZKeyspaceTableRuleID(keyspaceID, tableID, "leader")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZKeyspaceTableRuleID(key)).To(Equal(true))
		keyspace, table, roleType, err := ParseSingleAZKeyspaceTableRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(table).To(Equal(tableID))
		g.Expect(roleType).To(Equal("leader"))
	}
	{
		key := FormatSingleAZKeyspaceTableRuleID(keyspaceID, tableID, "")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZKeyspaceTableRuleID(key)).To(Equal(true))
		keyspace, table, roleType, err := ParseSingleAZKeyspaceTableRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(keyspace).To(Equal(keyspaceID))
		g.Expect(table).To(Equal(tableID))
		g.Expect(roleType).To(Equal(""))
	}
}

func TestFormatAndParseMultiAZRegionRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	regionID := uint64(1)
	{
		key := FormatMultiAZRegionRuleID(regionID, PrimaryZone)
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZRegionRuleID(key)).To(Equal(true))
		region, zoneType, err := ParseMultiAZRegionRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(region).To(Equal(regionID))
		g.Expect(zoneType).To(Equal(PrimaryZone))
	}
	{
		key := FormatMultiAZRegionRuleID(regionID, "")
		g.Expect(IsMultiAZRuleID(key)).To(Equal(true))
		g.Expect(IsMultiAZRegionRuleID(key)).To(Equal(true))
		region, zoneType, err := ParseMultiAZRegionRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(region).To(Equal(regionID))
		g.Expect(zoneType).To(Equal(""))
	}
}

func TestFormatAndParseSingleAZRegionRuleID(t *testing.T) {
	g := NewGomegaWithT(t)
	regionID := uint64(1)
	{
		key := FormatSingleAZRegionRuleID(regionID, "leader")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZRegionRuleID(key)).To(Equal(true))
		region, roleType, err := ParseSingleAZRegionRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(region).To(Equal(regionID))
		g.Expect(roleType).To(Equal("leader"))
	}
	{
		key := FormatSingleAZRegionRuleID(regionID, "")
		g.Expect(IsSingleAZRuleID(key)).To(Equal(true))
		g.Expect(IsSingleAZRegionRuleID(key)).To(Equal(true))
		region, roleType, err := ParseSingleAZRegionRuleID(key)
		g.Expect(err).NotTo(HaveOccurred())
		g.Expect(region).To(Equal(regionID))
		g.Expect(roleType).To(Equal(""))
	}
}

func TestFormatAndParseRangeKey(t *testing.T) {
	g := NewGomegaWithT(t)
	start := "12"
	end := "34"
	key := FormatRangeKey(start, end)
	s, e, err := ParseRangeKey(key)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(s).To(Equal(start))
	g.Expect(e).To(Equal(end))
}
