package api

import (
	"errors"
	"time"

	"github.com/pingcap/dbaas/billing2/utils/timeutils"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/novuhandler"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"go.uber.org/zap"
)

// @Summary Create Workflow
// @Schemes
// @Accept json
// @Produce json
// @Param workflow body forms.Workflow true "Workflow"
// @Success 200 {object} forms.Workflow
// @Router /workflow [post]
func (s *API) CreateWorkflow(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	flow := &forms.Workflow{}
	err := c.ShouldBindJSON(flow)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}

	return novuhandler.Get().CreateWorkflow(*flow)

}

// @Summary Update Workflow
// @Schemes
// @Accept json
// @Produce json
// @Param workflow body forms.Workflow true "Workflow"
// @Success 200 {object} forms.Workflow
// @Router /workflow [put]
func (s *API) UpdateWorkflow(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	flow := &forms.Workflow{}
	err := c.ShouldBindJSON(flow)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}

	return novuhandler.Get().UpdateWorkflow(*flow)

}

// @Summary DELETE Workflow
// @Schemes
// @Accept json
// @Produce json
// @Param workflow body forms.Workflow true "Workflow"
// @Success 200 {object} forms.Workflow
// @Router /workflow [DELETE]
func (s *API) DeleteWorkflow(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	flow := &forms.Workflow{}
	err := c.ShouldBindJSON(flow)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	err = novuhandler.Get().DeleteWorkflow(*flow)
	if err != nil {
		return nil, err

	}
	return forms.OK, nil

}

// @Summary Get WorkFlows
// @Schemes
// @Accept json
// @Produce json
// @Param page path string true "page"
// @Param page_size path string true "page_size"
// @Success 200 {object} forms.WorkFlows
// @Router /workflow/page/{page}/page_size/{page_size} [GET]
func (s *API) GetWorkflows(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &PageQuery{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	res, err := novuhandler.Get().GetWorkflows(*query.Page, *query.PageSize)
	if err != nil {
		return nil, err

	}
	return res, nil

}

type WorkFlowStruct struct {
	WorkflowID string `uri:"workflow_id" binding:"required"`
}
type PageQuery struct {
	Page     *int `uri:"page,default=0" binding:"required"`
	PageSize *int `uri:"page_size,default=20" binding:"required"`
}
type WorkFlowPageQueryStruct struct {
	WorkFlowStruct
	PageQuery
}

// @Summary Get Workflow
// @Schemes
// @Accept json
// @Produce json
// @Param workflow_id path string true "workflow_id"
// @Success 200 {object} forms.Workflow
// @Router /workflow/workflow_id/{workflow_id} [GET]
func (s *API) GetWorkflow(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &WorkFlowStruct{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	res, err := novuhandler.Get().GetWorkflow(query.WorkflowID)
	if err != nil {
		return nil, err

	}
	return res, nil

}

// @Summary Duplicate Workflow
// @Schemes
// @Accept json
// @Produce json
// @Param workflow_id path string true "workflow_id"
// @Success 200 {object} forms.Workflow
// @Router /workflow/workflow_id/{workflow_id} [POST]
func (s *API) DuplicateWorkflow(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &WorkFlowStruct{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	res, err := novuhandler.Get().DuplicateWorkflow(query.WorkflowID)
	if err != nil {
		return nil, err

	}
	return res, nil

}

// @Summary Bulk Trigger event
// @Schemes
// @Accept json
// @Produce json
// @Param trigger body forms.Trigger true "trigger"
// @Success 200 {object} forms.OKType
// @Router /bulk_trigger [post]
func (s *API) BulkTriggerEvent(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	trigger := &forms.Trigger{}
	err := c.ShouldBindJSON(trigger)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	if trigger.IsSendNow {
		trigger.ScheduleTime = timeutils.GetNow().Add(31 * time.Second)
	}
	if trigger.ScopeType == "" {
		trigger.ScopeType = constant.ScopeOrg
	}
	log.Info("BulkTriggerEvent", zap.Any("trigger", trigger))

	return novuhandler.Get().BulkTriggerEvent(trigger.TenantID, *trigger)
}

// @Summary  Trigger Broadcast
// @Schemes
// @Accept json
// @Produce json
// @Param trigger body forms.Trigger true "trigger"
// @Success 200 {object} forms.OKType
// @Router /broadcast_trigger [post]
func (s *API) BroadcastTriggerEvent(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	trigger := &forms.Trigger{}
	err := c.ShouldBindJSON(trigger)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	trigger.ScopeType = constant.ScopeOrg
	if trigger.IsSendNow {
		return nil, billing_errors.NewActionForbiddenError(errors.New("broadcast prohibited operation send now"))
	}
	log.Info("BroadcastTriggerEvent", zap.Any("trigger", trigger))
	if !operatorAuth(trigger.Operator) {
		log.Info("BroadcastTriggerEvent Prohibited operation ", zap.Any("trigger", trigger))
		return nil, billing_errors.NewActionForbiddenError(errors.New("broadcast prohibited operation"))

	}

	return novuhandler.Get().BroadcastTriggerEvent(*trigger)

}

type OperatorStruct struct {
	Operator string `uri:"operator" binding:"required"`
}

func operatorAuth(operator string) bool {
	if config.Get().GetBool(config.EnableBroadcast) {
		return true
	}
	operatorsMap := config.Get().GetStringMap(config.EnableBroadcastOperators)
	v, ok := operatorsMap[operator]
	if !ok {
		return false
	}
	return v.(bool)
}

// @Summary  Trigger Broadcast Auth
// @Schemes
// @Accept json
// @Produce json
// @Param operator path string true "operator"
// @Success 200 {object} forms.OKType
// @Router /broadcast_trigger/{operator}/auth [GET]
func (s *API) BroadcastTriggerAuth(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	operator := &OperatorStruct{}
	err := c.ShouldBindUri(operator)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}

	log.Info("BroadcastTriggerAuth", zap.Any("operator", operator))
	return operatorAuth(operator.Operator), nil
}

// @Summary Get Notifications By WorkflowID
// @Schemes
// @Accept json
// @Produce json
// @Param q query forms.NotificationQuery true "q"
// @Success 200 {object} forms.OpsNotifications
// @Router /notifications [GET]
func (s *API) GetNotificationsByWorkflowID(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &forms.NotificationQuery{}

	err := c.ShouldBindQuery(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	log.Info("GetNotificationsByWorkflowID", zap.Any("query", query))

	return novuhandler.Get().GetNotificationsByWorkflowID(*query)

}

// @Summary Get Workflow Notifications Summary By WorkflowID
// @Schemes
// @Accept json
// @Produce json
// @Param workflow_id path string true "workflow_id"
// @Success 200 {object} []forms.NotificationsSummary
// @Router /notifications/workflow_id/{workflow_id}/summary [GET]
func (s *API) GetSummaryByWorkflowID(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &WorkFlowStruct{}

	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	log.Info("GetSummaryByWorkflowID", zap.Any("query", query))

	return novuhandler.Get().GetNotificationsSummaryByWorkflowID(query.WorkflowID)

}

func InitializeUNCAPIRouter(router ginutils.MyRoute) {
	s := &API{}
	router.HandleWithError("POST", "/workflow", s.CreateWorkflow)
	router.HandleWithError("PUT", "/workflow", s.UpdateWorkflow)
	router.HandleWithError("DELETE", "/workflow", s.DeleteWorkflow)
	router.HandleWithError("GET", "/workflow/page/:page/page_size/:page_size", s.GetWorkflows)
	router.HandleWithError("GET", "/workflow/workflow_id/:workflow_id", s.GetWorkflow)
	router.HandleWithError("POST", "/workflow/workflow_id/:workflow_id", s.DuplicateWorkflow)
	router.HandleWithError("POST", "/bulk_trigger", s.BulkTriggerEvent)
	router.HandleWithError("POST", "/broadcast_trigger", s.BroadcastTriggerEvent)
	router.HandleWithError("GET", "/broadcast_trigger/:operator/auth", s.BroadcastTriggerAuth)

	router.HandleWithError("GET", "/notifications", s.GetNotificationsByWorkflowID)
	router.HandleWithError("GET", "/notifications/workflow_id/:workflow_id/summary", s.GetSummaryByWorkflowID)

}
