//go:build integration
// +build integration

package handler

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"

	response "github.com/pingcap/test-infra/common/model/rms/response"
	"github.com/pingcap/test-infra/services/rms/config"
	"github.com/pingcap/test-infra/services/rms/service/resource"
	"github.com/pingcap/test-infra/services/rms/utils"
)

func setup() {
	config.DefaultRMSConfiguration.Provider = "k8s"
	config.DefaultRMSConfiguration.MinIO.URL = "http://minio.pingcap.net:9000"
	config.DefaultRMSConfiguration.K8s.SDKKubeConfig = os.Getenv("KUBECONFIG")

	h = NewHandler(resource.NewDefaultService(), resource.NewDefaultStatisticsService())
	e = NewHTTPServer(h)
}

var (
	createTestbedRequest = []byte(`{
  "generateName":"testbed-",
  "items":[
    {
      "name":"tc-1",
      "type":"TIDB_CLUSTER",
      "spec":{
        "pd":{
          "replicas":1,
          "image":"pingcap/pd:v5.0.0"
        },
        "tidb":{
          "replicas":1,
          "image":"pingcap/tidb:v5.0.0"
        },
        "tikv":{
          "replicas":1,
          "image":"pingcap/tikv:v5.0.0"
        }
      },
      "qos":{
        "tidb":{
          "podGroup":"cluster-1",
          "exclusive":false
        },
        "tikv":{
          "podGroup":"cluster-1",
          "exclusive":true
        }
      }
    },
    {
      "name":"workload",
      "type":"WORKLOAD_NODE",
      "spec":{
        "container":{
          "name":"alpineblock",
          "image":"alpine:latest",
          "command":[
            "tail",
            "-f",
            "/dev/null"
          ],
          "resources":{
            "requests":{
              "memory":"64Mi",
              "cpu":"250m",
              "storage":"1Gi"
            }
          }
        }
      },
      "qos":{
        "podGroup":"cluster-1",
        "exclusive":true
      }
    },
    {
      "name":"tidb-lightning",
      "type":"TIDB_LIGHTNING",
      "spec":{
        "image":"docker.io/pingcap/tidb-lightning:v5.0.1",
        "resources":{
          "requests":{
            "memory":"64Mi",
            "cpu":"250m",
            "storage":"1Gi"
          }
        }
      },
      "qos":{
        "podGroup":"cluster-1",
        "exclusive":true
      }
    },
    {
      "name":"mysql",
      "type":"MYSQL_NODE",
      "spec":{
        "image":"docker.io/mysql:8.0.25",
        "port":3306,
        "resources":{
          "requests":{
            "memory":"1Gi",
            "cpu":"250m",
            "storage":"1Gi"
          }
        },
        "env":{
          "MYSQL_ALLOW_EMPTY_PASSWORD":"yes",
          "MYSQL_ROOT_HOST":"%%"
        }
      }
    },
    {
      "name":"br",
      "type":"BR_NODE",
      "spec":{
        "image":"docker.io/pingcap/br:v5.0.1",
        "resources":{
          "requests":{
            "memory":"64Mi",
            "cpu":"250m",
            "storage":"1Gi"
          }
        }
      }
    },
    {
      "name":"dm",
      "type":"DM_CLUSTER",
      "spec":{
        "master":{
          "replicas":1,
          "image":"pingcap/dm:v2.0.3"
        },
        "worker":{
          "replicas":1,
          "image":"pingcap/dm:v2.0.3"
        }
      }
    }
  ],
  "qos":[
    {
      "podGroup":"cluster-1"
    }
  ]
}
`)
)

func TestHandlerCreateGetDeleteTestbed(t *testing.T) {
	setup()
	// create a testbed
	req := httptest.NewRequest(echo.POST, "/api/v1/testbeds", bytes.NewReader(createTestbedRequest))
	req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
	rec := httptest.NewRecorder()
	ctx := utils.NewContext(e.NewContext(req, rec))
	utils.SetUser(ctx, &utils.User{Name: "unittest"})
	assert.Nil(t, h.CreateTestbed(ctx))
	res := response.CreateTestbedResponse{}
	assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &res))

	testbedName := res.Name

	// get testbed by name
	req = httptest.NewRequest(echo.GET, "/api/v1/testbeds/:name", nil)
	rec = httptest.NewRecorder()
	ctx = utils.NewContext(e.NewContext(req, rec))
	ctx.SetPath("/api/v1/testbeds/:name")
	ctx.SetParamNames("name")
	ctx.SetParamValues(testbedName)
	assert.Nil(t, h.GetTestbed(ctx))

	if assert.Equal(t, http.StatusOK, rec.Code) {
		res := response.GetTestbedResponse{}
		assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &res))

		assert.Equal(t, testbedName, res.Name)
		assert.Equal(t, 6, len(res.Items))
		assert.Equal(t, "tc-1", res.Items[0].Name)
		assert.Equal(t, "workload", res.Items[1].Name)
		assert.Equal(t, "tidb-lightning", res.Items[2].Name)
		assert.Equal(t, "mysql", res.Items[3].Name)
		assert.Equal(t, "br", res.Items[4].Name)
		assert.Equal(t, "dm", res.Items[5].Name)
		assert.Equal(t, testbedName, res.Items[0].Testbed)
		assert.Equal(t, testbedName, res.Items[1].Testbed)
	}

	// delete testbed
	req = httptest.NewRequest(echo.DELETE, "/api/v1/testbeds/:name", nil)
	rec = httptest.NewRecorder()
	ctx = utils.NewContext(e.NewContext(req, rec))
	ctx.SetPath("/api/v1/testbeds/:name")
	ctx.SetParamNames("name")
	ctx.SetParamValues(testbedName)
	utils.SetUser(ctx, &utils.User{Name: "unittest"})
	assert.Nil(t, h.DeleteTestbed(ctx))

	if assert.Equal(t, http.StatusOK, rec.Code) {
		res := new(string)
		assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &res))
		assert.Equal(t, "", *res)
	}
}
