package controller

import (
	"dataservices/commons/ginparser"
	dto "dataservices/internal/dto/dataapi"
	"dataservices/internal/entity"
	"dataservices/internal/repository"
	service "dataservices/internal/service/central"
	"net/http"
	"strconv"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/gin-gonic/gin"
)

// Online Endpoints godoc
// @Summary online endpoints
// @Description online endpoints
// @Tags dataapi
// @Param org_id   path string true "org ID"
// @Param project_id path string true "project ID"
// @Param app_id path string true "app ID"
// @Param endpoint_id path string true "endpoint ID"
// @Param request_body body entity.DeployEndpointReq true "request_body"
// @Accept json
// @Produce json
// @Success 200 {object} dto.EndpointPublishRes
// @Router /orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/online [post]
func OnlineEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	validateKeys := &[]string{ginparser.PARAM_ORG_ID, ginparser.PARAM_PROJECT_ID, ginparser.PARAM_APP_ID, ginparser.PARAM_ENDPOINT_ID}
	params := ginparser.NewCommonParamsByGin(c)
	createdBy, _ := params.GetUserEmail()
	validateErr := params.ValidateUrl(validateKeys)
	if validateErr != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/online[post]-OnlineEndpoint param validate failed!", zap.Error(validateErr), zap.String("user", createdBy))
		c.Error(validateErr)
		return
	}

	var req entity.DeployEndpointReq
	if c.Request.ContentLength > 0 {
		if err := params.BindParam(&req); err != nil {
			tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/online[post]-OnlineEndpoint bind param failed", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
			c.Error(err)
			return
		}
	}

	// version, err := service.CreateOnlineEndpoint(ctx, params.EndpointID, createdBy)
	endpoint, err := repository.GetEndpoint(params.EndpointID)
	if err != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/online[post]-OnlineEndpoint GetEndpoint failed!", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
		c.Error(err)
		return
	}

	var deployName string
	if req.DeployName != "" {
		deployName = req.DeployName
	} else {
		deployName = "Deploy Endpoint: " + endpoint.Endpoint
	}
	deployLog, err := service.TriggerEndpointDeployFromUI(ctx, params.AppID, params.EndpointID, createdBy, deployName)
	if err != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/online[post]-OnlineEndpoint execution failed!", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
		c.Error(err)
		return
	}

	var res dto.EndpointPublishRes
	res.BasicRes = dto.DefaultSuccessBasicRes()
	res.Data.Version = strconv.FormatUint(deployLog.ID, 10)
	c.JSON(http.StatusOK, res)
}

// Check Endpoints Deploy Status godoc
// @Summary check endpoint deploy status
// @Description check endpoint deploy status
// @Tags dataapi
// @Param org_id   path string true "org ID"
// @Param project_id path string true "project ID"
// @Param app_id path string true "app ID"
// @Param endpoint_id path string true "endpoint ID"
// @Param version path string true "version"
// @Accept json
// @Produce json
// @Success 200 {object} dto.EndpointDeployRes
// @Router /orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/version/{version}/status [get]
func CheckEndpointDeployStatus(c *gin.Context) {
	ctx := c.Request.Context()
	validateKeys := &[]string{ginparser.PARAM_ORG_ID, ginparser.PARAM_PROJECT_ID, ginparser.PARAM_APP_ID, ginparser.PARAM_ENDPOINT_ID, ginparser.PARAM_VERSION}
	params := ginparser.NewCommonParamsByGin(c)
	createdBy, _ := params.GetUserEmail()
	validateErr := params.ValidateUrl(validateKeys)
	if validateErr != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/version/{version}/status[get]-CheckEndpointDeployStatus param validate failed!", zap.Error(validateErr), zap.String("user", createdBy))
		c.Error(validateErr)
		return
	}

	endpointID := params.EndpointID
	version := params.Version
	isCompleted, err := service.CheckEndpointDeployComplete(ctx, endpointID, version)
	if err != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/version/{version}/status[get]-CheckEndpointDeployStatus CheckEndpointDeployComplete failed!", zap.Error(err), zap.String("user", createdBy))
		commonError(c, err)
		return
	}

	var res dto.EndpointDeployRes
	res.BaseResp = dto.SuccessBaseResp()
	res.Data.Completed = isCompleted
	res.Data.Version = version
	c.JSON(http.StatusOK, res)
}

// Offline Endpoints godoc
// @Summary offline endpoints
// @Description offline endpoints
// @Tags dataapi
// @Param org_id   path string true "org ID"
// @Param project_id path string true "project ID"
// @Param app_id path string true "app ID"
// @Param endpoint_id path string true "endpoint ID"
// @Accept json
// @Produce json
// @Success 200 {object} dto.BaseResp
// @Router /orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/offline [put]
func OfflineEndpoint(c *gin.Context) {
	ctx := c.Request.Context()
	validateKeys := &[]string{ginparser.PARAM_ORG_ID, ginparser.PARAM_PROJECT_ID, ginparser.PARAM_APP_ID}
	params := ginparser.NewCommonParamsByGin(c)
	createdBy, _ := params.GetUserEmail()
	validateErr := params.ValidateUrl(validateKeys)
	if validateErr != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/offline[put]-OfflineEndpoint param validate failed!", zap.Error(validateErr), zap.String("user", createdBy))
		c.Error(validateErr)
		return
	}
	// version, err := service.CreateOnlineEndpoint(ctx, params.EndpointID, createdBy)
	endpoint, err := repository.GetEndpoint(params.EndpointID)
	if err != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/offline[put]-OfflineEndpoint GetEndpoint failed!", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
		c.Error(err)
		return
	}
	deployLog, err := service.TriggerEndpointUndeployFromUI(ctx, params.AppID, params.EndpointID, createdBy, "Undeploy Endpoint: "+endpoint.Endpoint)
	if err != nil {
		tilog.Error(ctx, "DS-Central-/orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/offline[put]-OfflineEndpoint execution failed!", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
		c.Error(err)
		return
	}

	var res dto.EndpointPublishRes
	res.BasicRes = dto.DefaultSuccessBasicRes()
	res.Data.Version = strconv.FormatUint(deployLog.ID, 10)
	c.JSON(http.StatusOK, res)
}

// // List Online Endpoints godoc
// // @Summary list online endpoints by appid
// // @Description list online endpoints by appid
// // @Tags dataapi
// // @Param org_id   path string true "org ID"
// // @Param project_id path string true "project ID"
// // @Param app_id path string true "app ID"
// // @Accept json
// // @Produce json
// // @Success 200 {object} dto.ListEndpointPublishRes
// // @Router /orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/online/records [get]
// func ListOnlineEndpoint(c *gin.Context) {
// 	ctx := c.Request.Context()
// 	validateKeys := &[]string{ginparser.PARAM_ORG_ID, ginparser.PARAM_PROJECT_ID, ginparser.PARAM_APP_ID}
// 	params := ginparser.NewCommonParamsByGin(c)
// 	createdBy, _ := params.GetUserEmail()
// 	validateErr := params.ValidateUrl(validateKeys)
// 	if validateErr != nil {
// 		tilog.Error(ctx, "ListOnlineEndpoint param validate failed! err:%v, user:%s", validateErr, createdBy))
// 		c.Error(validateErr)
// 		return
// 	}

// 	resp, err := service.ListOnlineEndpoint(ctx, params.AppID)
// 	if err != nil {
// 		tilog.Error(ctx, "ListOnlineEndpoint failed! dataappId:%d,err:%v, user:%s", params.AppID, err, createdBy))
// 		c.Error(err)
// 		return
// 	}

// 	respJson := &dto.ListEndpointPublishRes{
// 		BasicRes: dto.DefaultSuccessBasicRes(),
// 		Data:     resp,
// 	}
// 	c.JSON(http.StatusOK, respJson)
// }

// List Endpoint Versions godoc
// @Summary list endpoint versions by endpointid
// @Description list endpoint versions by endpointid
// @Tags dataapi
// @Param org_id   path string true "org ID"
// @Param project_id path string true "project ID"
// @Param app_id path string true "app ID"
// @Param endpoint_id path string true "endpoint ID"
// @Accept json
// @Produce json
// @Success 200 {object} dto.ListEndpointPublishLogRes
// @Router /orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/versions [get]
func ListEndpointPublishVersions(c *gin.Context) {
	ctx := c.Request.Context()
	validateKeys := &[]string{ginparser.PARAM_ORG_ID, ginparser.PARAM_PROJECT_ID, ginparser.PARAM_APP_ID, ginparser.PARAM_ENDPOINT_ID}
	params := ginparser.NewCommonParamsByGin(c)
	createdBy, _ := params.GetUserEmail()
	validateErr := params.ValidateUrl(validateKeys)
	if validateErr != nil {
		tilog.Error(ctx, "DS-Central-orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/versions[get]-ListEndpointPublishVersions ListEndpointPublishLog param validate failed!", zap.Error(validateErr), zap.String("user", createdBy))
		c.Error(validateErr)
		return
	}

	resp, err := service.ListEndpointPublishLog(ctx, params.EndpointID)
	if err != nil {
		tilog.Error(ctx, "DS-Central-orgs/{org_id}/projects/{project_id}/apps/{app_id}/endpoints/{endpoint_id}/versions[get]-ListEndpointPublishVersions ListEndpointPublishLog execution failed!", zap.Error(err), zap.Uint64("endpoint_id", params.EndpointID), zap.String("user", createdBy))
		c.Error(err)
		return
	}

	respJson := &dto.ListEndpointPublishLogRes{
		BasicRes: dto.DefaultSuccessBasicRes(),
		Data:     dto.ConvertEndpointPublishHistory(resp),
	}
	c.JSON(http.StatusOK, respJson)
}
