package handler

import (
	"context"
	"eslogad-be/internal/appcontext"
	"net/http"
	"strconv"

	"eslogad-be/internal/contract"

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

type LetterService interface {
	CreateIncomingLetter(ctx context.Context, req *contract.CreateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
	GetIncomingLetterByID(ctx context.Context, id uuid.UUID) (*contract.IncomingLetterResponse, error)
	ListIncomingLetters(ctx context.Context, req *contract.ListIncomingLettersRequest) (*contract.ListIncomingLettersResponse, error)
	UpdateIncomingLetter(ctx context.Context, id uuid.UUID, req *contract.UpdateIncomingLetterRequest) (*contract.IncomingLetterResponse, error)
	SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error

	CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error)
	GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error)

	CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
	UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
}

type LetterHandler struct{ svc LetterService }

func NewLetterHandler(svc LetterService) *LetterHandler { return &LetterHandler{svc: svc} }

func (h *LetterHandler) CreateIncomingLetter(c *gin.Context) {
	var req contract.CreateIncomingLetterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, &contract.ErrorResponse{Error: "invalid body", Code: http.StatusBadRequest})
		return
	}
	resp, err := h.svc.CreateIncomingLetter(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(http.StatusCreated, contract.BuildSuccessResponse(resp))
}

func (h *LetterHandler) GetIncomingLetter(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.GetIncomingLetterByID(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 *LetterHandler) ListIncomingLetters(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	status := c.Query("status")
	query := c.Query("q")
	var statusPtr *string
	var queryPtr *string
	if status != "" {
		statusPtr = &status
	}
	if query != "" {
		queryPtr = &query
	}
	req := &contract.ListIncomingLettersRequest{Page: page, Limit: limit, Status: statusPtr, Query: queryPtr}
	resp, err := h.svc.ListIncomingLetters(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 *LetterHandler) UpdateIncomingLetter(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.UpdateIncomingLetterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.UpdateIncomingLetter(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 *LetterHandler) DeleteIncomingLetter(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid id", Code: 400})
		return
	}
	if err := h.svc.SoftDeleteIncomingLetter(c.Request.Context(), id); err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, &contract.SuccessResponse{Message: "deleted"})
}

func (h *LetterHandler) CreateDispositions(c *gin.Context) {
	appCtx := appcontext.FromGinContext(c.Request.Context())
	var req contract.CreateLetterDispositionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	req.FromDepartment = appCtx.DepartmentID
	resp, err := h.svc.CreateDispositions(c.Request.Context(), &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(201, contract.BuildSuccessResponse(resp))
}

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

func (h *LetterHandler) CreateDiscussion(c *gin.Context) {
	letterID, err := uuid.Parse(c.Param("letter_id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid letter_id", Code: 400})
		return
	}
	var req contract.CreateLetterDiscussionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.CreateDiscussion(c.Request.Context(), letterID, &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(201, contract.BuildSuccessResponse(resp))
}

func (h *LetterHandler) UpdateDiscussion(c *gin.Context) {
	letterID, err := uuid.Parse(c.Param("letter_id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid letter_id", Code: 400})
		return
	}
	discussionID, err := uuid.Parse(c.Param("discussion_id"))
	if err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid discussion_id", Code: 400})
		return
	}
	var req contract.UpdateLetterDiscussionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, &contract.ErrorResponse{Error: "invalid body", Code: 400})
		return
	}
	resp, err := h.svc.UpdateDiscussion(c.Request.Context(), letterID, discussionID, &req)
	if err != nil {
		c.JSON(500, &contract.ErrorResponse{Error: err.Error(), Code: 500})
		return
	}
	c.JSON(200, contract.BuildSuccessResponse(resp))
}
