package mgmthttpcli

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"

	"github.com/go-resty/resty/v2"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

var _ = Describe("NextGenClusterAgent", func() {
	var server *httptest.Server

	AfterEach(func() {
		if server != nil {
			server.Close()
		}
	})

	It("sends prepare replace-node instance_id target and decodes state", func() {
		var (
			receivedMethod string
			receivedPath   string
			receivedBody   []byte
		)
		server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			receivedMethod = r.Method
			receivedPath = r.URL.Path
			receivedBody, _ = io.ReadAll(r.Body)

			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"phase":"REPLACE_NODE_PHASE_PREPARED","message":"prepared","podName":"db-1-tidb-0","instanceId":"i-0733d30f7fe215f74","componentKind":"TiDB","oldNode":"node-a","warmUpPod":"replace-node-warm-up","warmUpNode":"node-b"}`))
		}))

		client := &ngClusterAgent{
			core:         resty.New().SetBaseURL(server.URL),
			sharedPoolID: "2045660260714151936",
		}

		resp, err := client.PrepareReplaceNode(context.Background(), &PrepareReplaceNodeReq{
			OperationID:    "42",
			ResourcePoolID: "2045660260714151936",
			InstanceID:     "i-0733d30f7fe215f74",
			Force:          true,
		})

		Expect(err).NotTo(HaveOccurred())
		Expect(receivedMethod).To(Equal(http.MethodPost))
		Expect(receivedPath).To(Equal("/proxy/nextgen/resourcePools/2045660260714151936/dataplane/proxy/sharedPools/2045660260714151936/cluster-agent/tidb2045660260714151936/api/v1/clusters/2045660260714151936:prepareReplaceNode"))

		var body map[string]any
		Expect(json.Unmarshal(receivedBody, &body)).To(Succeed())
		Expect(body).To(HaveKeyWithValue("operationId", "42"))
		Expect(body).To(HaveKeyWithValue("instanceId", "i-0733d30f7fe215f74"))
		Expect(body).To(HaveKeyWithValue("force", true))
		Expect(body).NotTo(HaveKey("clusterId"))
		Expect(body).NotTo(HaveKey("cluster_id"))
		Expect(body).NotTo(HaveKey("resourcePoolId"))
		Expect(body).NotTo(HaveKey("resource_pool_id"))
		Expect(body).NotTo(HaveKey("podName"))
		Expect(body).NotTo(HaveKey("pod_name"))

		Expect(resp.Phase).To(Equal("REPLACE_NODE_PHASE_PREPARED"))
		Expect(resp.PodName).To(Equal("db-1-tidb-0"))
		Expect(resp.InstanceID).To(Equal("i-0733d30f7fe215f74"))
		Expect(resp.ComponentKind).To(Equal("TiDB"))
		Expect(resp.OldNode).To(Equal("node-a"))
		Expect(resp.WarmUpNode).To(Equal("node-b"))
	})

	It("uses get, commit, and abort replace-node paths", func() {
		receivedPaths := []string{}
		receivedBodies := []map[string]any{}
		server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			receivedPaths = append(receivedPaths, r.URL.Path)
			rawBody, _ := io.ReadAll(r.Body)
			var body map[string]any
			Expect(json.Unmarshal(rawBody, &body)).To(Succeed())
			receivedBodies = append(receivedBodies, body)
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"phase":"REPLACE_NODE_PHASE_COMMITTED"}`))
		}))

		client := &ngClusterAgent{
			core:         resty.New().SetBaseURL(server.URL),
			sharedPoolID: "2045660260714151936",
		}

		req := &ReplaceNodeOperationReq{OperationID: "42", ResourcePoolID: "2045660260714151936"}
		_, err := client.GetReplaceNodeOperation(context.Background(), req)
		Expect(err).NotTo(HaveOccurred())
		_, err = client.CommitReplaceNode(context.Background(), req)
		Expect(err).NotTo(HaveOccurred())
		_, err = client.AbortReplaceNode(context.Background(), req)
		Expect(err).NotTo(HaveOccurred())

		Expect(receivedPaths).To(Equal([]string{
			"/proxy/nextgen/resourcePools/2045660260714151936/dataplane/proxy/sharedPools/2045660260714151936/cluster-agent/tidb2045660260714151936/api/v1/clusters/2045660260714151936:getReplaceNodeOperation",
			"/proxy/nextgen/resourcePools/2045660260714151936/dataplane/proxy/sharedPools/2045660260714151936/cluster-agent/tidb2045660260714151936/api/v1/clusters/2045660260714151936:commitReplaceNode",
			"/proxy/nextgen/resourcePools/2045660260714151936/dataplane/proxy/sharedPools/2045660260714151936/cluster-agent/tidb2045660260714151936/api/v1/clusters/2045660260714151936:abortReplaceNode",
		}))
		Expect(receivedBodies).To(HaveLen(3))
		for _, body := range receivedBodies {
			Expect(body).To(HaveKeyWithValue("operationId", "42"))
			Expect(body).NotTo(HaveKey("clusterId"))
			Expect(body).NotTo(HaveKey("cluster_id"))
			Expect(body).NotTo(HaveKey("resourcePoolId"))
			Expect(body).NotTo(HaveKey("resource_pool_id"))
		}
	})
})
