package k8supgrade

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	regionalpb "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	"go.uber.org/zap"
	"k8s.io/apimachinery/pkg/api/errors"

	"github.com/tidbcloud/infra-provider/regional-server/pkg/router/interceptor"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/service/k8supgrade"
)

type Handler struct {
	svc *k8supgrade.Service
}

func NewHandler(svc *k8supgrade.Service) *Handler {
	return &Handler{
		svc: svc,
	}
}

func (h *Handler) ListK8sInformation(c *gin.Context) {
	req := new(regionalpb.ListK8SInformationRequest)
	req.Version = c.Query("version")

	list, err := h.svc.ListK8sInformation(c, req)
	if err != nil {
		log.Error("failed to list k8s information", zap.String("version", req.Version), zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.SucceedPb(c, http.StatusOK, &list)
	}
}

func (h *Handler) GetK8sInformation(c *gin.Context) {
	req := new(regionalpb.GetK8SInformationRequest)
	req.Name = c.Param("name")

	info, err := h.svc.GetK8sInformation(c, req)
	if err != nil {
		log.Error("failed to get k8s information", zap.String("name", req.Name), zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.SucceedPb(c, http.StatusOK, info)
	}
}

func (h *Handler) CreateUpgradeOperation(c *gin.Context) {
	req := new(regionalpb.CreateUpgradeOperationRequest)
	if ok := interceptor.HandleJsonPbRequestFromBody(c, req); !ok {
		err := fmt.Errorf("failed to handle json pb request from body %v", req)
		log.Error(err.Error())
		interceptor.Fail(c, err)
	}
	if err := h.svc.CreateOrUpdateUpgradeOperation(c, req.UpgradeOperation); err != nil {
		log.Error("failed to create or update upgrade operation CR", zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.Succeed(c, http.StatusOK, nil)
	}
}

func (h *Handler) UpdateUpgradeOperation(c *gin.Context) {
	req := new(regionalpb.UpdateUpgradeOperationRequest)
	if ok := interceptor.HandleJsonPbRequestFromBody(c, req); !ok {
		err := fmt.Errorf("failed to handle json pb request from body %v", req)
		log.Error(err.Error())
		interceptor.Fail(c, err)
	}
	if err := h.svc.CreateOrUpdateUpgradeOperation(c, req.UpgradeOperation); err != nil {
		log.Error("failed to create or update upgrade operation CR", zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.Succeed(c, http.StatusOK, nil)
	}
}

func (h *Handler) GetUpgradeOperation(c *gin.Context) {
	req := &regionalpb.GetUpgradeOperationRequest{
		Name: c.Param("name"),
	}
	uo, err := h.svc.GetUpgradeOperation(c, req)
	if err == nil {
		interceptor.SucceedPb(c, http.StatusOK, uo)
		return
	}
	log.Error("failed to get upgrade operation CR", zap.String("name", req.Name), zap.Error(err))
	if errors.IsNotFound(err) {
		interceptor.Succeed(c, http.StatusNotFound, nil)
		return
	}
	interceptor.Fail(c, err)
}

func (h *Handler) DeleteUpgradeOperation(c *gin.Context) {
	req := &regionalpb.DeleteUpgradeOperationRequest{
		Name: c.Param("name"),
	}
	err := h.svc.DeleteUpgradeOperation(c, req)
	if err == nil {
		interceptor.Succeed(c, http.StatusOK, nil)
		return
	}
	log.Error("failed to delete upgrade operation CR", zap.String("name", req.Name), zap.Error(err))
	if errors.IsNotFound(err) {
		interceptor.Succeed(c, http.StatusNotFound, nil)
		return
	}
	interceptor.Fail(c, err)
}

func (h *Handler) PatchUpgradeOperationAnnotations(c *gin.Context) {
	req := new(regionalpb.PatchUpgradeOperationAnnotationsRequest)
	if ok := interceptor.HandleJsonPbRequestFromBody(c, req); !ok {
		err := fmt.Errorf("failed to handle json pb request from body %v", req)
		log.Error(err.Error())
		interceptor.Fail(c, err)
		return
	}
	req.Name = c.Param("name")
	if err := h.svc.PatchUpgradeOperationAnnotations(c, req); err != nil {
		log.Error("failed to patch upgrade operation annotations", zap.String("name", req.Name), zap.Error(err))
		interceptor.Fail(c, err)
		return
	}
	interceptor.Succeed(c, http.StatusOK, nil)
}
