package api

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/admin/forms"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/errors"
)

// @Summary AddProvider
// @Tags Provider
// @Description AddProvider
// @Accept  json
// @Produce json
// @Param provider body forms.Provider true "provider"
// @Success 200 {object} forms.EmptyResponse
// @Router /providers [post]
func AddProvider(c *gin.Context) {
	req := forms.Provider{}

	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	if req.Status == "" {
		req.Status = string(entity.ProviderStatusActive)
	}
	switch req.Status {
	case string(entity.ProviderStatusInactive), string(entity.ProviderStatusActive):
	// pass
	default:
		Fail(c, errors.BadRequestf("bad provider status"), http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	if err := userContext.AddProvider(req.Name, req.Status); err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, nil, http.StatusOK)
}

// @Summary ListProviders
// @Tags Provider
// @Description ListProviders
// @Accept  json
// @Produce json
// @Success 200 {object} forms.ListProvidersResp
// @Router /providers [get]
func ListProviders(c *gin.Context) {
	userContext := GetUserContext(c)
	dbRecords, err := userContext.ListProviders()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	count, err := userContext.GetProvidersCount()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	items := []forms.Provider{}
	for _, item := range dbRecords {
		items = append(items, forms.Provider{Name: item.Name, Status: item.Status})
	}

	result := forms.ListProvidersResp{
		Total: count,
		Items: items,
	}

	Success(c, result, http.StatusOK)
}

// @Summary AddRegion
// @Tags Provider
// @Description AddRegion
// @Accept  json
// @Produce json
// @Param provider path string true "provider"
// @Param region body forms.ProviderRegion true "region"
// @Success 200 {object} forms.ProviderRegion
// @Router /providers/{provider}/regions [post]
func AddRegion(c *gin.Context) {
	reqUri := forms.GetProviderReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	req := forms.ProviderRegion{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req.Provider = reqUri.Provider

	userContext := GetUserContext(c)

	region, err := buildInternalRegion(req)
	if err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	item, err := userContext.AddRegion(region)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, buildAPIRegionItem(item), http.StatusOK)
}

// @Summary UpdateRegion
// @Tags Provider
// @Description UpdateRegion
// @Accept  json
// @Produce json
// @Param provider path string true "provider"
// @Param region_id path string true "region_id"
// @Param region body forms.ProviderRegion true "region"
// @Success 200 {object} forms.ProviderRegion
// @Router /providers/{provider}/regions/{region_id} [put]
func UpdateRegion(c *gin.Context) {
	reqUri := forms.GetProviderAndRegionIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	req := forms.ProviderRegion{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req.ID = reqUri.RegionID
	req.Provider = reqUri.Provider

	userContext := GetUserContext(c)
	region, err := buildInternalRegion(req)
	if err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	item, err := userContext.UpdateRegion(region)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, buildAPIRegionItem(item), http.StatusOK)
}

// @Summary ListRegions
// @Tags Provider
// @Description ListRegions
// @Accept  json
// @Produce json
// @Param provider path string true "provider"
// @Success 200 {object} forms.ListRegionResp
// @Router /providers/{provider}/regions [get]
func ListRegions(c *gin.Context) {
	reqUri := forms.GetProviderReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)

	dbRecords, err := userContext.ListRegions(reqUri.Provider)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	count, err := userContext.GetListRegionsCount(reqUri.Provider)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	items := []forms.ProviderRegion{}
	for _, item := range dbRecords {
		items = append(items, buildAPIRegionItem(item))
	}

	result := forms.ListRegionResp{
		Total: count,
		Items: items,
	}

	Success(c, result, http.StatusOK)
}

// @Summary DeleteRegion
// @Tags Provider
// @Description DeleteRegion
// @Accept  json
// @Produce json
// @Param provider path string true "provider"
// @Param region_id path string true "region_id"
// @Success 200 {object} forms.EmptyResponse
// @Router /providers/{provider}/regions/{region_id} [delete]
func DeleteRegion(c *gin.Context) {
	reqUri := forms.GetProviderAndRegionIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	if err := userContext.DeleteRegion(reqUri.Provider, reqUri.RegionID); err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, nil, http.StatusOK)
}

// @Summary GetRegionByID
// @Tags Provider
// @Description GetRegionByID
// @Accept  json
// @Produce json
// @Param provider path string true "provider"
// @Param region_id path string true "region_id"
// @Success 200 {object} forms.ProviderRegion
// @Router /providers/{provider}/regions/{region_id} [get]
func GetRegionByID(c *gin.Context) {
	reqUri := forms.GetProviderAndRegionIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	item, err := userContext.GetRegionByID(reqUri.Provider, reqUri.RegionID)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, buildAPIRegionItem(item), http.StatusOK)
}
