/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package integrationtest_test

import (
	"bytes"
	"encoding/json"
	"io"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"

	. "github.com/apache/servicecomb-service-center/integration"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/widuu/gojson"
)

var _ = Describe("MicroService Api Test", func() {
	var serviceName = "integrationtestInstances"
	var serviceId = ""
	var serviceAppId = "integrationtestAppIdInstance"
	var serviceVersion = "0.0.2"
	Context("Tesing MicroService Tags API's", func() {
		BeforeEach(func() {
			schema := []string{"testSchema"}
			properties := map[string]string{"attr1": "aa"}
			servicemap := map[string]interface{}{
				"serviceName": serviceName + strconv.Itoa(rand.Int()),
				"appId":       serviceAppId,
				"version":     serviceVersion,
				"description": "examples",
				"level":       "FRONT",
				"schemas":     schema,
				"status":      "UP",
				"properties":  properties,
			}
			bodyParams := map[string]interface{}{
				"service": servicemap,
			}
			body, _ := json.Marshal(bodyParams)
			bodyBuf := bytes.NewReader(body)
			req, _ := http.NewRequest(POST, SCURL+REGISTERMICROSERVICE, bodyBuf)
			req.Header.Set("X-Domain-Name", "default")
			resp, err := scclient.Do(req)
			Expect(err).To(BeNil())
			defer resp.Body.Close()

			// Validate the service creation
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			respbody, _ := io.ReadAll(resp.Body)
			serviceId = gojson.Json(string(respbody)).Get("serviceId").Tostring()
			Expect(len(serviceId)).Should(BeNumerically("==", LengthUUID))
		})

		AfterEach(func() {
			if serviceId != "" {
				url := strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", serviceId, 1)
				req, _ := http.NewRequest(DELETE, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, _ := scclient.Do(req)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
			}

		})

		By("Create Micro-Service Tag API", func() {
			It("Create MicroService tags", func() {
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))
			})

			It("Create MicroService tags with empty collections, should be pass", func() {
				bodyParams := map[string]interface{}{}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				tags := map[string]interface{}{}
				bodyParams = map[string]interface{}{
					"tags": tags,
				}
				url = strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ = json.Marshal(bodyParams)
				bodyBuf = bytes.NewReader(body)
				req, _ = http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err = scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))
			})

			It("Create MicroService tags with invalid serviceID", func() {
				tags := map[string]interface{}{
					"testkey": "testValue",
				}
				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", "XXX", 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
			})
		})

		By("Get Micro-Service Tag API", func() {
			It("Get Tags for MicroService", func() {
				//Add Tag
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Get Tags
				<-time.After(time.Second)
				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
				req, _ = http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				req.Header.Set("X-ConsumerId", serviceId)
				resp, _ = scclient.Do(req)
				respbody, _ := io.ReadAll(resp.Body)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
				tagsStruct := map[string]interface{}{}
				json.Unmarshal(respbody, &tagsStruct)
				Expect(tagsStruct).To(Equal(bodyParams))
			})

			It("Get Empty Tags for MicroService", func() {
				//Get Tags
				url := strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
				req, _ := http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				req.Header.Set("X-ConsumerId", serviceId)
				resp, _ := scclient.Do(req)
				respbody, _ := io.ReadAll(resp.Body)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
				Expect(string(bytes.TrimSpace(respbody))).To(Equal("{}"))
			})

			It("Get Tags for Invalid MicroService", func() {
				//Get Tags
				url := strings.Replace(GETTAGS, ":serviceId", "XXXX", 1)
				req, _ := http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, _ := scclient.Do(req)
				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
			})

		})
		By("Update Micro-Service Tag API", func() {
			It("Update MicroService tag with proper value", func() {
				//Add Tag
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Update Tags
				<-time.After(time.Second)
				url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
				url = strings.Replace(url, ":key", "testkey", 1)
				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err = scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Verify the Tags
				<-time.After(time.Second)
				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
				req, _ = http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				req.Header.Set("X-ConsumerId", serviceId)
				resp, _ = scclient.Do(req)
				respbody, _ := io.ReadAll(resp.Body)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
				tagsStruct := map[string]interface{}{}
				json.Unmarshal(respbody, &tagsStruct)
				tags = map[string]interface{}{
					"testkey": "newValue",
				}

				newTags := map[string]interface{}{
					"tags": tags,
				}
				Expect(tagsStruct).To(Equal(newTags))
			})

			It("Update MicroService tag with non-exsisting tags", func() {
				//Add Tag
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Update Tags
				<-time.After(time.Second)
				url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
				url = strings.Replace(url, ":key", "unknownkey", 1)
				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err = scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))

			})

			It("Update MicroService tag with non-exsisting serviceID", func() {
				url := strings.Replace(UPDATETAG, ":serviceId", "XXXXX", 1)
				url = strings.Replace(url, ":key", "unknownkey", 1)
				req, _ := http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
			})

		})
		By("Delete Micro-Service Tag API", func() {
			It("Delete MicroService tag with proper value", func() {
				//Add Tag
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Delete the tag
				<-time.After(time.Second)
				url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
				url = strings.Replace(url, ":key", "testkey", 1)
				req, _ = http.NewRequest(DELETE, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err = scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//verify Delete
				<-time.After(time.Second)
				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
				req, _ = http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				req.Header.Set("X-ConsumerId", serviceId)
				resp, _ = scclient.Do(req)
				respbody, _ := io.ReadAll(resp.Body)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
				Expect(string(bytes.TrimSpace(respbody))).To(Equal("{}"))
			})

			It("Delete MicroService tag with non-exsisting tags", func() {
				//Add Tag
				tags := map[string]interface{}{
					"testkey": "testValue",
				}

				bodyParams := map[string]interface{}{
					"tags": tags,
				}
				url := strings.Replace(ADDTAGE, ":serviceId", serviceId, 1)
				body, _ := json.Marshal(bodyParams)
				bodyBuf := bytes.NewReader(body)
				req, _ := http.NewRequest(POST, SCURL+url, bodyBuf)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()

				Expect(resp.StatusCode).To(Equal(http.StatusOK))

				//Delete the tag
				<-time.After(time.Second)
				url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
				url = strings.Replace(url, ":key", "unknowTag", 1)
				req, _ = http.NewRequest(DELETE, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err = scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))

				//verify Non-deleted of exsiting tag
				<-time.After(time.Second)
				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
				req, _ = http.NewRequest(GET, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				req.Header.Set("X-ConsumerId", serviceId)
				resp, _ = scclient.Do(req)
				respbody, _ := io.ReadAll(resp.Body)
				Expect(resp.StatusCode).To(Equal(http.StatusOK))
				tagsStruct := map[string]interface{}{}
				json.Unmarshal(respbody, &tagsStruct)
				Expect(tagsStruct).To(Equal(bodyParams))
			})

			It("Delete MicroService tag with non-exsiting service id", func() {
				//Delete the tag
				url := strings.Replace(DELETETAG, ":serviceId", "XXX", 1)
				url = strings.Replace(url, ":key", "testkey", 1)
				req, _ := http.NewRequest(DELETE, SCURL+url, nil)
				req.Header.Set("X-Domain-Name", "default")
				resp, err := scclient.Do(req)
				Expect(err).To(BeNil())
				defer resp.Body.Close()
				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
			})
		})
	})
})
