package handler

import (
	"context"
	"eslogad-be/internal/appcontext"

	"eslogad-be/internal/contract"

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

type DispositionRouteService interface {
	Create(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.DispositionRouteResponse, error)
	CreateOrUpdate(ctx context.Context, req *contract.CreateDispositionRouteRequest) (*contract.BulkCreateDispositionRouteResponse, error)
	Update(ctx context.Context, id uuid.UUID, req *contract.UpdateDispositionRouteRequest) (*contract.DispositionRouteResponse, error)
	Get(ctx context.Context, id uuid.UUID) (*contract.DispositionRouteResponse, error)
	ListByFromDept(ctx context.Context, from uuid.UUID) (*contract.ListDispositionRoutesResponse, error)
	SetActive(ctx context.Context, id uuid.UUID, active bool) error
	ListGrouped(ctx context.Context) (*contract.ListDispositionRoutesGroupedResponse, error)
	ListAll(ctx context.Context) (*contract.ListDispositionRoutesDetailedResponse, error)
}

type DispositionRouteHandler struct{ svc DispositionRouteService }

func NewDispositionRouteHandler(svc DispositionRouteService) *DispositionRouteHandler {
	return &DispositionRouteHandler{svc: svc}
}

// Create handles both single and bulk route creation with upsert logic
func (h *DispositionRouteHandler) Create(c *gin.Context) {
	var req contract.CreateDispositionRouteRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body: " + err.Error(), Code: 400})
		return
	}
	
	// Validate request
	if len(req.ToDepartmentIDs) == 0 {
		c.JSON(400, &contract.ErrorResponse{Error: "to_department_ids cannot be empty", Code: 400})
		return
	}
	
	// If single route, use Create for backward compatibility
	if len(req.ToDepartmentIDs) == 1 {
		resp, err := h.svc.Create(c.Request.Context(), &req)
		if err != nil {
			c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
			return
		}
		c.JSON(201, contract.BuildSuccessResponse(resp))
		return
	}
	
	// For multiple routes, use bulk create/update
	bulkResp, err := h.svc.CreateOrUpdate(c.Request.Context(), &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(201, contract.BuildSuccessResponse(bulkResp))
}

// BulkCreateOrUpdate explicitly handles bulk create/update operations
func (h *DispositionRouteHandler) BulkCreateOrUpdate(c *gin.Context) {
	var req contract.CreateDispositionRouteRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body: " + err.Error(), Code: 400})
		return
	}
	
	// Validate request
	if len(req.ToDepartmentIDs) == 0 {
		c.JSON(400, &contract.ErrorResponse{Error: "to_department_ids cannot be empty", Code: 400})
		return
	}
	
	resp, err := h.svc.CreateOrUpdate(c.Request.Context(), &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	
	c.JSON(200, contract.BuildSuccessResponse(resp))
}

func (h *DispositionRouteHandler) Update(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	var req contract.UpdateDispositionRouteRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.Update(c.Request.Context(), id, &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}

func (h *DispositionRouteHandler) Get(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	resp, err := h.svc.Get(c.Request.Context(), id)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}

func (h *DispositionRouteHandler) ListByFromDept(c *gin.Context) {
	appCtx := appcontext.FromGinContext(c.Request.Context())

	resp, err := h.svc.ListByFromDept(c.Request.Context(), appCtx.DepartmentID)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}

func (h *DispositionRouteHandler) SetActive(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	toggle := c.Query("active")
	active := toggle != "false"
	if err := h.svc.SetActive(c.Request.Context(), id, active); err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, &contract.SuccessResponse{Message: "updated"})
}

// ListGrouped returns all disposition routes grouped by from_department_id
func (h *DispositionRouteHandler) ListGrouped(c *gin.Context) {
	resp, err := h.svc.ListGrouped(c.Request.Context())
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}

// ListAll returns all disposition routes with department details
func (h *DispositionRouteHandler) ListAll(c *gin.Context) {
	resp, err := h.svc.ListAll(c.Request.Context())
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}
