package task

import (
	"net"
	"testing"
)

func Test_gkeCIDRDispatcher(t *testing.T) {
	type cidr struct {
		region                     string
		pod, node, service, master string
		isError                    bool

		// CIDR when set placeholder
		podP, nodeP, serviceP, masterP string
		isSetPrefixPlaceholderError    bool
	}
	cases := []cidr{
		{
			region:   "10.250.0.0/19",
			pod:      "10.250.0.0/21",
			node:     "10.250.8.0/23",
			service:  "10.250.12.0/23",
			master:   "10.250.14.0/28",
			podP:     "10.250.16.0/21",
			nodeP:    "10.250.24.0/23",
			serviceP: "10.250.28.0/23",
			masterP:  "10.250.30.0/28",
		},
		{
			region:                      "172.30.192.0/20",
			pod:                         "172.30.192.0/21",
			node:                        "172.30.200.0/23",
			service:                     "172.30.204.0/23",
			master:                      "172.30.206.0/28",
			isSetPrefixPlaceholderError: true,
		},
		{
			region:  "172.30.0.0/21",
			pod:     "",
			node:    "",
			service: "",
			master:  "",
			isError: true,
		},
	}

	for _, c := range cases {
		p, err := newGKECIDRDispatcher(c.region)
		if err != nil {
			if !c.isError {
				t.Fatalf("unexpected error")
			}
			continue
		}
		t.Log("test default")
		p.Default()
		if p.PodIPv4CIDRBlock() != c.pod {
			t.Fatalf("pod IPv4 CIDR not correct, expected: %s, return: %s", c.pod, p.PodIPv4CIDRBlock())
		}
		if p.NodeIPv4CIDRBlock() != c.node {
			t.Fatalf("node IPv4 CIDR not correct, expected: %s, return: %s", c.node, p.NodeIPv4CIDRBlock())
		}
		if p.ServiceIPv4CIDRBlock() != c.service {
			t.Fatalf("service IPv4 CIDR not correct, expected: %s, return: %s", c.service, p.ServiceIPv4CIDRBlock())
		}
		if p.MasterIPv4CIDRBlock() != c.master {
			t.Fatalf("master IPv4 CIDR not correct, expected: %s, return: %s", c.master, p.MasterIPv4CIDRBlock())
		}

		// Set prefix placeholder
		t.Log("test set prefix placeholder")
		err = p.SetPrefixPlaceholder()
		if err != nil {
			if !c.isSetPrefixPlaceholderError {
				t.Fatalf("unexpected error")
			}
			continue
		}
		if p.PodIPv4CIDRBlock() != c.podP {
			t.Fatalf("pod IPv4 CIDR not correct, expected: %s, return: %s", c.pod, p.PodIPv4CIDRBlock())
		}
		if p.NodeIPv4CIDRBlock() != c.nodeP {
			t.Fatalf("node IPv4 CIDR not correct, expected: %s, return: %s", c.node, p.NodeIPv4CIDRBlock())
		}
		if p.ServiceIPv4CIDRBlock() != c.serviceP {
			t.Fatalf("service IPv4 CIDR not correct, expected: %s, return: %s", c.service, p.ServiceIPv4CIDRBlock())
		}
		if p.MasterIPv4CIDRBlock() != c.masterP {
			t.Fatalf("master IPv4 CIDR not correct, expected: %s, return: %s", c.master, p.MasterIPv4CIDRBlock())
		}
	}
}

func TestSplitSubnet(t *testing.T) {
	testCases := []struct {
		cidr       string
		subnetSize int
		expected   int
	}{
		{"192.168.1.0/24", 8, 8},
	}

	for _, tc := range testCases {
		_, ipv4Net, _ := net.ParseCIDR(tc.cidr)

		subnets, _ := SplitSubnet(ipv4Net, tc.subnetSize)

		if len(subnets) != tc.expected {
			t.Errorf("failed split subnets, expected %d subnets,but got %d subnets", tc.expected, len(subnets))
		}
		if subnets[0].String() != "192.168.1.0/27" {
			t.Errorf("failed split subnets, expected 192.168.1.0/27,but got %s", subnets[0].String())
		}
		if subnets[7].String() != "192.168.1.224/27" {
			t.Errorf("failed split subnets, expected 192.168.1.224/27,but got %s", subnets[7].String())
		}
	}
}

func Test_GkeCidrAllocate(t *testing.T) {
	type cidr struct {
		region                     string
		pod, node, service, master string
	}
	cases := []cidr{
		{
			region:  "10.250.0.0/19",
			pod:     "10.250.0.0/20",
			node:    "10.250.16.0/22",
			service: "10.250.20.0/22",
			master:  "10.250.24.0/28",
		},
	}

	for _, c := range cases {
		p, err := newGKECIDRDispatcher(c.region)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		t.Log("test cidr allocate")
		err = p.Allocate()
		if err != nil {
			t.Fatal(err)
		}
		if p.PodIPv4CIDRBlock() != c.pod {
			t.Fatalf("pod IPv4 CIDR not correct, expected: %s, return: %s", c.pod, p.PodIPv4CIDRBlock())
		}
		if p.NodeIPv4CIDRBlock() != c.node {
			t.Fatalf("node IPv4 CIDR not correct, expected: %s, return: %s", c.node, p.NodeIPv4CIDRBlock())
		}
		if p.ServiceIPv4CIDRBlock() != c.service {
			t.Fatalf("service IPv4 CIDR not correct, expected: %s, return: %s", c.service, p.ServiceIPv4CIDRBlock())
		}
		if p.MasterIPv4CIDRBlock() != c.master {
			t.Fatalf("master IPv4 CIDR not correct, expected: %s, return: %s", c.master, p.MasterIPv4CIDRBlock())
		}
	}
}
