package controller

import (
	"strconv"
	"web-qudo-be/app/database/entity"
	"web-qudo-be/app/middleware"
	"web-qudo-be/app/module/approval_workflow_steps/request"
	"web-qudo-be/app/module/approval_workflow_steps/service"
	"web-qudo-be/utils/paginator"
	utilRes "web-qudo-be/utils/response"
	utilVal "web-qudo-be/utils/validator"

	"github.com/gofiber/fiber/v2"
	"github.com/rs/zerolog"
)

// Helper functions for parsing query parameters
func parseUintPointer(s string) *uint {
	if s == "" {
		return nil
	}
	if val, err := strconv.ParseUint(s, 10, 32); err == nil {
		uval := uint(val)
		return &uval
	}
	return nil
}

func parseIntPointer(s string) *int {
	if s == "" {
		return nil
	}
	if val, err := strconv.Atoi(s); err == nil {
		return &val
	}
	return nil
}

func parseStringPointer(s string) *string {
	if s == "" {
		return nil
	}
	return &s
}

func parseBoolPointer(s string) *bool {
	if s == "" {
		return nil
	}
	if val, err := strconv.ParseBool(s); err == nil {
		return &val
	}
	return nil
}

type approvalWorkflowStepsController struct {
	approvalWorkflowStepsService service.ApprovalWorkflowStepsService
	Log                          zerolog.Logger
}

type ApprovalWorkflowStepsController interface {
	All(c *fiber.Ctx) error
	Show(c *fiber.Ctx) error
	Save(c *fiber.Ctx) error
	Update(c *fiber.Ctx) error
	Delete(c *fiber.Ctx) error
	GetByWorkflow(c *fiber.Ctx) error
	GetByRole(c *fiber.Ctx) error
	BulkSave(c *fiber.Ctx) error
	Reorder(c *fiber.Ctx) error
}

func NewApprovalWorkflowStepsController(approvalWorkflowStepsService service.ApprovalWorkflowStepsService, log zerolog.Logger) ApprovalWorkflowStepsController {
	return &approvalWorkflowStepsController{
		approvalWorkflowStepsService: approvalWorkflowStepsService,
		Log:                          log,
	}
}

// All ApprovalWorkflowSteps
// @Summary      Get all ApprovalWorkflowSteps
// @Description  API for getting all ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        workflowId query int false "Workflow ID filter"
// @Param        stepOrder query int false "Step order filter"
// @Param        stepName query string false "Step name filter"
// @Param        userLevelId query int false "User level ID filter"
// @Param        isOptional query bool false "Is optional filter"
// @Param        isActive query bool false "Is active filter"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps [get]
func (_i *approvalWorkflowStepsController) All(c *fiber.Ctx) error {
	_, err := paginator.Paginate(c)
	if err != nil {
		return err
	}

	req := request.GetApprovalWorkflowStepsRequest{
		WorkflowID:  parseUintPointer(c.Query("workflowId")),
		StepOrder:   parseIntPointer(c.Query("stepOrder")),
		StepName:    parseStringPointer(c.Query("stepName")),
		UserLevelID: parseUintPointer(c.Query("userLevelId")),
		IsOptional:  parseBoolPointer(c.Query("isOptional")),
		IsActive:    parseBoolPointer(c.Query("isActive")),
		Page:        1,
		Limit:       10,
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	_i.Log.Info().Interface("clientId", clientId).Msg("")

	approvalWorkflowStepsData, paging, err := _i.approvalWorkflowStepsService.GetAll(clientId, req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps list successfully retrieved"},
		Data:     approvalWorkflowStepsData,
		Meta:     paging,
	})
}

// Show ApprovalWorkflowSteps
// @Summary      Get one ApprovalWorkflowSteps
// @Description  API for getting one ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        id path int true "ApprovalWorkflowSteps ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/{id} [get]
func (_i *approvalWorkflowStepsController) Show(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid ID format")
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	approvalWorkflowStepsData, err := _i.approvalWorkflowStepsService.FindOne(clientId, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully retrieved"},
		Data:     approvalWorkflowStepsData,
	})
}

// Save ApprovalWorkflowSteps
// @Summary      Save ApprovalWorkflowSteps
// @Description  API for saving ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param 	     payload body request.CreateApprovalWorkflowStepsRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps [post]
func (_i *approvalWorkflowStepsController) Save(c *fiber.Ctx) error {
	req := new(request.CreateApprovalWorkflowStepsRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	// Convert request to entity
	step := &entity.ApprovalWorkflowSteps{
		WorkflowId:          req.WorkflowID,
		StepOrder:           req.StepOrder,
		StepName:            req.StepName,
		RequiredUserLevelId: req.ApproverRoleID,
		CanSkip:             &req.IsOptional,
	}

	approvalWorkflowStepsData, err := _i.approvalWorkflowStepsService.Create(clientId, step)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully created"},
		Data:     approvalWorkflowStepsData,
	})
}

// Update ApprovalWorkflowSteps
// @Summary      Update ApprovalWorkflowSteps
// @Description  API for updating ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        id path int true "ApprovalWorkflowSteps ID"
// @Param 	     payload body request.UpdateApprovalWorkflowStepsRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/{id} [put]
func (_i *approvalWorkflowStepsController) Update(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid ID format")
	}

	req := new(request.UpdateApprovalWorkflowStepsRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	// Convert request to entity
	step := &entity.ApprovalWorkflowSteps{}
	if req.StepOrder != nil {
		step.StepOrder = *req.StepOrder
	}
	if req.StepName != nil {
		step.StepName = *req.StepName
	}
	if req.ApproverRoleID != nil {
		step.RequiredUserLevelId = *req.ApproverRoleID
	}
	if req.IsOptional != nil {
		step.CanSkip = req.IsOptional
	}

	err = _i.approvalWorkflowStepsService.Update(clientId, uint(id), step)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully updated"},
	})
}

// Delete ApprovalWorkflowSteps
// @Summary      Delete ApprovalWorkflowSteps
// @Description  API for deleting ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        id path int true "ApprovalWorkflowSteps ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/{id} [delete]
func (_i *approvalWorkflowStepsController) Delete(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid ID format")
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	err = _i.approvalWorkflowStepsService.Delete(clientId, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully deleted"},
	})
}

// GetByWorkflow ApprovalWorkflowSteps
// @Summary      Get ApprovalWorkflowSteps by Workflow ID
// @Description  API for getting ApprovalWorkflowSteps by Workflow ID
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        workflowId path int true "Workflow ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/workflow/{workflowId} [get]
func (_i *approvalWorkflowStepsController) GetByWorkflow(c *fiber.Ctx) error {
	workflowId, err := strconv.Atoi(c.Params("workflowId"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid workflow ID format")
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	approvalWorkflowStepsData, err := _i.approvalWorkflowStepsService.GetByWorkflowID(clientId, uint(workflowId))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps by workflow successfully retrieved"},
		Data:     approvalWorkflowStepsData,
	})
}

// GetByRole ApprovalWorkflowSteps
// @Summary      Get ApprovalWorkflowSteps by Role ID
// @Description  API for getting ApprovalWorkflowSteps by Role ID
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        roleId path int true "Role ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/role/{roleId} [get]
func (_i *approvalWorkflowStepsController) GetByRole(c *fiber.Ctx) error {
	roleId, err := strconv.Atoi(c.Params("roleId"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid role ID format")
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	approvalWorkflowStepsData, err := _i.approvalWorkflowStepsService.GetByWorkflowID(clientId, uint(roleId))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps by role successfully retrieved"},
		Data:     approvalWorkflowStepsData,
	})
}

// BulkSave ApprovalWorkflowSteps
// @Summary      Bulk create ApprovalWorkflowSteps
// @Description  API for bulk creating ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param 	     payload body request.BulkCreateApprovalWorkflowStepsRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/bulk [post]
func (_i *approvalWorkflowStepsController) BulkSave(c *fiber.Ctx) error {
	req := new(request.BulkCreateApprovalWorkflowStepsRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	// Convert request to entities
	var steps []*entity.ApprovalWorkflowSteps
	for _, stepReq := range req.Steps {
		step := &entity.ApprovalWorkflowSteps{
			WorkflowId:          stepReq.WorkflowID,
			StepOrder:           stepReq.StepOrder,
			StepName:            stepReq.StepName,
			RequiredUserLevelId: stepReq.ApproverRoleID,
			CanSkip:             &stepReq.IsOptional,
		}
		steps = append(steps, step)
	}

	approvalWorkflowStepsData, err := _i.approvalWorkflowStepsService.BulkCreate(clientId, req.WorkflowID, steps)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully bulk created"},
		Data:     approvalWorkflowStepsData,
	})
}

// Reorder ApprovalWorkflowSteps
// @Summary      Reorder ApprovalWorkflowSteps
// @Description  API for reordering ApprovalWorkflowSteps
// @Tags         ApprovalWorkflowSteps
// @Security     Bearer
// @Param        X-Client-Key header string true "Insert the X-Client-Key"
// @Param        workflowId path int true "Workflow ID"
// @Param 	     payload body request.ReorderApprovalWorkflowStepsRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /approval-workflow-steps/workflow/{workflowId}/reorder [put]
func (_i *approvalWorkflowStepsController) Reorder(c *fiber.Ctx) error {
	workflowId, err := strconv.Atoi(c.Params("workflowId"))
	if err != nil {
		return utilRes.ErrorBadRequest(c, "Invalid workflow ID format")
	}

	req := new(request.ReorderApprovalWorkflowStepsRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	// Get ClientId from context
	clientId := middleware.GetClientID(c)

	// Convert request to expected format
	stepOrders := req.ToStepOrders()

	err = _i.approvalWorkflowStepsService.ReorderSteps(clientId, uint(workflowId), stepOrders)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"ApprovalWorkflowSteps successfully reordered"},
	})
}
