package api

import (
	"net/http"

	"github.com/tidbcloud/account/internel/svc/sqluser"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/account/admin/forms"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

// @Summary ListDbUsers
// @tags DbUsers
// @Accept  json
// @Produce json
// @Param cluster_id path string true "cluster_id"
// @Param search query forms.ListDbUsersReq  true "search"
// @Success 200 {object} forms.ListDbUsersRsp
// @Router /clusters/:cluster_id/db-users [get]
func ListDbUsers(c *gin.Context) {
	ctx := c.Request.Context()

	reqUri := forms.GetClusterIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.ListDbUsersReq{}
	if err := c.ShouldBindQuery(&req); err != nil {
		tilog.Error(ctx, "ListDbUsers err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req.ClusterId = reqUri.ClusterID

	svc, _ := sqluser.GetDbUserWatchDogSvc()

	ret, err := svc.ListDbUsers(ctx, &sqluser.ListDbUsersReq{
		ClusterID:       req.ClusterId,
		Plugin:          req.Plugin,
		PasswordExpired: req.PasswordExpired,
		AccountLocked:   req.AccountLocked,
		IgnoreUsers:     req.IgnoreUsers,
		Users:           req.Users,
		ListDbUserType:  req.ListDbUserType,
	})
	if err != nil {
		tilog.Error(ctx, "ListDbUsers err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	var retUsers []forms.DbUserDisplay
	for _, u := range ret.DbUsers {
		display := forms.DbUserDisplay{
			TargetValue: u.TargetValue,
			TargetType:  u.TargetType,
			Username:    u.UserName,
			BuiltinRole: u.BuiltinRole,
			CustomRoles: u.CustomRoles,
			Plugin:      u.AuthMethod,
		}
		retUsers = append(retUsers, display)
	}
	var inClusterUsers []forms.DbUserDisplay
	for _, u := range ret.InClusterDbUsers {
		display := forms.DbUserDisplay{
			TargetValue: u.TargetValue,
			TargetType:  u.TargetType,
			Username:    u.UserName,
			BuiltinRole: u.BuiltinRole,
			CustomRoles: u.CustomRoles,
			Plugin:      u.AuthMethod,
		}
		inClusterUsers = append(inClusterUsers, display)
	}

	rsp := forms.ListDbUsersRsp{
		DbUsers:          retUsers,
		InClusterDbUsers: inClusterUsers,
	}

	Success(c, rsp, http.StatusOK)
}

// @Summary TestDbUser
// @tags DbUsers
// @Accept  json
// @Produce json
// @Param DbUsers body forms.TestDbUserReq true "TestDbUser"
// @Success 200 {object} forms.EmptyResponse
// @Router /clusters/:cluster_id/test-db-user [post]
func TestDbUser(c *gin.Context) {
	ctx := c.Request.Context()

	reqUri := forms.GetClusterIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.TestDbUserReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		tilog.Error(ctx, "TestDbUser err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req.ClusterId = reqUri.ClusterID

	svc, _ := sqluser.GetDbUserWatchDogSvc()
	err := svc.TestDbUser(ctx, &sqluser.TestDbUserReq{
		ClusterID:      req.ClusterId,
		TargetValue:    req.TargetValue,
		TargetType:     req.TargetType,
		QuerySQL:       "select now();",
		TestDbUserType: req.TestDbUserType,
	})

	if err != nil {
		tilog.Error(ctx, "TestDbUser err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, "ok", http.StatusOK)
}

// @Summary TestDbUserJwt
// @tags DbUsers
// @Accept  json
// @Produce json
// @Param DbUsers body forms.TestDbUserJwtReq true "TestDbUser"
// @Success 200 {object} forms.EmptyResponse
// @Router /clusters/:cluster_id/jwt [post]
func TestDbUserJwt(c *gin.Context) {
	ctx := c.Request.Context()

	reqUri := forms.GetClusterIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.TestDbUserJwtReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		tilog.Error(ctx, "TestDbUser err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}

	svc, _ := sqluser.GetDbUserWatchDogSvc()

	//operator, _, err := svc.GetClusterOperator(ctx, param)
	result, err := svc.TestDbUserJwt(ctx, &sqluser.TestDbUserJwtReq{
		ClusterID: reqUri.ClusterID,
		UserName:  req.DbUser,
		Jwt:       req.JWT,
		QuerySQL:  "select now();",
	})
	if err != nil {
		tilog.Info(ctx, "TestDbUserJwt err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusOK)
		return
	}
	Success(c, result, http.StatusOK)
}

// @Summary GetDbUserJwt
// @tags DbUsers
// @Accept  json
// @Produce json
// @Param cluster_id path string  true "cluster_id"
// @Param param query forms.GetDbUserJwtReq  true "param"
// @Success 200 {object} forms.GetDbUserJwtResp
// @Router /clusters/:cluster_id/jwt [get]
func GetDbUserJwt(c *gin.Context) {
	ctx := c.Request.Context()
	tilog.Info(ctx, "TestDbUser ")
	reqUri := forms.GetClusterIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.GetDbUserJwtReq{}
	if err := c.ShouldBindQuery(&req); err != nil {
		tilog.Error(ctx, "GetDbUserJwt err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	tilog.Info(ctx, "GetDbUserJwt ", zap.Any("req", req))
	svc, _ := sqluser.GetDbUserWatchDogSvc()
	param := &sqluser.GetClusterOperatorReq{ClusterID: reqUri.ClusterID, TargetType: req.TargetType, TargetValue: req.TargetValue}
	operator, _, err := svc.GetClusterOperator(ctx, param)

	if err != nil {
		tilog.Info(ctx, "GetDbUserJwt err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	resp := &forms.GetDbUserJwtResp{
		DbUser: operator.Username,
		JWT:    operator.Credential,
	}
	Success(c, resp, http.StatusOK)
}
