package handler

import (
	"context"
	"net/http"
	"strconv"

	"eslogad-be/internal/contract"

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

type ApprovalFlowService interface {
	CreateApprovalFlow(ctx context.Context, req *contract.ApprovalFlowRequest) (*contract.ApprovalFlowResponse, error)
	GetApprovalFlow(ctx context.Context, id uuid.UUID) (*contract.ApprovalFlowResponse, error)
	GetApprovalFlowByDepartment(ctx context.Context, departmentID uuid.UUID) (*contract.ApprovalFlowResponse, error)
	UpdateApprovalFlow(ctx context.Context, id uuid.UUID, req *contract.ApprovalFlowRequest) (*contract.ApprovalFlowResponse, error)
	DeleteApprovalFlow(ctx context.Context, id uuid.UUID) error
	ListApprovalFlows(ctx context.Context, req *contract.ListApprovalFlowsRequest) (*contract.ListApprovalFlowsResponse, error)
}

type AdminApprovalFlowHandler struct {
	svc ApprovalFlowService
}

func NewAdminApprovalFlowHandler(svc ApprovalFlowService) *AdminApprovalFlowHandler {
	return &AdminApprovalFlowHandler{svc: svc}
}

func (h *AdminApprovalFlowHandler) CreateApprovalFlow(c *gin.Context) {
	var req contract.ApprovalFlowRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
		return
	}

	if len(req.Steps) == 0 {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "at least one approval step is required", Code: http.StatusBadRequest})
		return
	}

	for i, step := range req.Steps {
		if step.ApproverRoleID == nil && step.ApproverUserID == nil {
			c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
				Error: "step " + strconv.Itoa(i+1) + " must have either approver_role_id or approver_user_id",
				Code:  http.StatusBadRequest,
			})
			return
		}
		if step.ApproverRoleID != nil && step.ApproverUserID != nil {
			c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
				Error: "step " + strconv.Itoa(i+1) + " cannot have both approver_role_id and approver_user_id",
				Code:  http.StatusBadRequest,
			})
			return
		}
	}

	resp, err := h.svc.CreateApprovalFlow(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) GetApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	resp, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) GetApprovalFlowByDepartment(c *gin.Context) {
	departmentID, err := uuid.Parse(c.Param("department_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid department_id", Code: http.StatusBadRequest})
		return
	}

	resp, err := h.svc.GetApprovalFlowByDepartment(c.Request.Context(), departmentID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) UpdateApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	var req contract.ApprovalFlowRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
		return
	}

	if len(req.Steps) == 0 {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "at least one approval step is required", Code: http.StatusBadRequest})
		return
	}

	for i, step := range req.Steps {
		if step.ApproverRoleID == nil && step.ApproverUserID == nil {
			c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
				Error: "step " + strconv.Itoa(i+1) + " must have either approver_role_id or approver_user_id",
				Code:  http.StatusBadRequest,
			})
			return
		}
		if step.ApproverRoleID != nil && step.ApproverUserID != nil {
			c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
				Error: "step " + strconv.Itoa(i+1) + " cannot have both approver_role_id and approver_user_id",
				Code:  http.StatusBadRequest,
			})
			return
		}
	}

	resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) DeleteApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	if err := h.svc.DeleteApprovalFlow(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, &contract.SuccessResponse{Message: "approval flow deleted"})
}

func (h *AdminApprovalFlowHandler) ListApprovalFlows(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	offset := (page - 1) * limit

	departmentIDStr := c.Query("department_id")
	isActiveStr := c.Query("is_active")

	var departmentID *uuid.UUID
	var isActive *bool

	if departmentIDStr != "" {
		if id, err := uuid.Parse(departmentIDStr); err == nil {
			departmentID = &id
		}
	}

	if isActiveStr != "" {
		if isActiveStr == "true" {
			active := true
			isActive = &active
		} else if isActiveStr == "false" {
			active := false
			isActive = &active
		}
	}

	req := &contract.ListApprovalFlowsRequest{
		Limit:        limit,
		Offset:       offset,
		DepartmentID: departmentID,
		IsActive:     isActive,
	}

	resp, err := h.svc.ListApprovalFlows(c.Request.Context(), req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) ActivateApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	// Get the current flow
	flow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	// Update only the IsActive field
	req := &contract.ApprovalFlowRequest{
		DepartmentID: flow.DepartmentID,
		Name:         flow.Name,
		Description:  flow.Description,
		IsActive:     true,
		Steps:        make([]contract.ApprovalFlowStepRequest, len(flow.Steps)),
	}

	// Copy existing steps
	for i, step := range flow.Steps {
		req.Steps[i] = contract.ApprovalFlowStepRequest{
			StepOrder:      step.StepOrder,
			ParallelGroup:  step.ParallelGroup,
			ApproverRoleID: step.ApproverRoleID,
			ApproverUserID: step.ApproverUserID,
			Required:       step.Required,
		}
	}

	resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) DeactivateApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	// Get the current flow
	flow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	// Update only the IsActive field
	req := &contract.ApprovalFlowRequest{
		DepartmentID: flow.DepartmentID,
		Name:         flow.Name,
		Description:  flow.Description,
		IsActive:     false,
		Steps:        make([]contract.ApprovalFlowStepRequest, len(flow.Steps)),
	}

	// Copy existing steps
	for i, step := range flow.Steps {
		req.Steps[i] = contract.ApprovalFlowStepRequest{
			StepOrder:      step.StepOrder,
			ParallelGroup:  step.ParallelGroup,
			ApproverRoleID: step.ApproverRoleID,
			ApproverUserID: step.ApproverUserID,
			Required:       step.Required,
		}
	}

	resp, err := h.svc.UpdateApprovalFlow(c.Request.Context(), id, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusOK, contract.BuildSuccessResponse(resp))
}

func (h *AdminApprovalFlowHandler) CloneApprovalFlow(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid id", Code: http.StatusBadRequest})
		return
	}

	var cloneReq struct {
		DepartmentID uuid.UUID `json:"department_id" validate:"required"`
		Name         string    `json:"name" validate:"required"`
	}

	if err := c.ShouldBindJSON(&cloneReq); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
		return
	}

	// Get the source flow
	sourceFlow, err := h.svc.GetApprovalFlow(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	// Create new flow request with cloned data
	req := &contract.ApprovalFlowRequest{
		DepartmentID: cloneReq.DepartmentID,
		Name:         cloneReq.Name,
		Description:  sourceFlow.Description,
		IsActive:     false, // New cloned flow starts as inactive
		Steps:        make([]contract.ApprovalFlowStepRequest, len(sourceFlow.Steps)),
	}

	// Copy steps from source flow
	for i, step := range sourceFlow.Steps {
		req.Steps[i] = contract.ApprovalFlowStepRequest{
			StepOrder:      step.StepOrder,
			ParallelGroup:  step.ParallelGroup,
			ApproverRoleID: step.ApproverRoleID,
			ApproverUserID: step.ApproverUserID,
			Required:       step.Required,
		}
	}

	resp, err := h.svc.CreateApprovalFlow(c.Request.Context(), req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: http.StatusInternalServerError})
		return
	}

	c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}
