package handler

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/util"
	"strconv"

	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/logger"
	"apskel-pos-be/internal/service"
	"apskel-pos-be/internal/validator"

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

type OrganizationHandler struct {
	organizationService   service.OrganizationService
	organizationValidator validator.OrganizationValidator
}

func NewOrganizationHandler(
	organizationService service.OrganizationService,
	organizationValidator validator.OrganizationValidator,
) *OrganizationHandler {
	return &OrganizationHandler{
		organizationService:   organizationService,
		organizationValidator: organizationValidator,
	}
}

func (h *OrganizationHandler) CreateOrganization(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.CreateOrganizationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(c.Request.Context()).WithError(err).Error("OrganizationHandler::CreateOrganization -> request binding failed")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::CreateOrganization")
		return
	}

	validationError, validationErrorCode := h.organizationValidator.ValidateCreateOrganizationRequest(&req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::CreateOrganization")
		return
	}

	organizationResponse := h.organizationService.CreateOrganization(ctx, contextInfo, &req)
	if organizationResponse.HasErrors() {
		errorResp := organizationResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::CreateOrganization -> Failed to create organization from service")
	}

	util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::CreateOrganization")
}

func (h *OrganizationHandler) UpdateOrganization(c *gin.Context) {
	ctx := c.Request.Context()

	organizationIDStr := c.Param("id")
	organizationID, err := uuid.Parse(organizationIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::UpdateOrganization -> Invalid organization ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
		return
	}

	var req contract.UpdateOrganizationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::UpdateOrganization -> request binding failed")
		validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
		return
	}

	validationError, validationErrorCode := h.organizationValidator.ValidateUpdateOrganizationRequest(&req)
	if validationError != nil {
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
		return
	}

	organizationResponse := h.organizationService.UpdateOrganization(ctx, organizationID, &req)
	if organizationResponse.HasErrors() {
		errorResp := organizationResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::UpdateOrganization -> Failed to update organization from service")
	}

	util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::UpdateOrganization")
}

func (h *OrganizationHandler) DeleteOrganization(c *gin.Context) {
	ctx := c.Request.Context()

	organizationIDStr := c.Param("id")
	organizationID, err := uuid.Parse(organizationIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::DeleteOrganization -> Invalid organization ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::DeleteOrganization")
		return
	}

	organizationResponse := h.organizationService.DeleteOrganization(ctx, organizationID)
	if organizationResponse.HasErrors() {
		errorResp := organizationResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::DeleteOrganization -> Failed to delete organization from service")
	}

	util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::DeleteOrganization")
}

func (h *OrganizationHandler) GetOrganization(c *gin.Context) {
	ctx := c.Request.Context()

	organizationIDStr := c.Param("id")
	organizationID, err := uuid.Parse(organizationIDStr)
	if err != nil {
		logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::GetOrganization -> Invalid organization ID")
		validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::GetOrganization")
		return
	}

	organizationResponse := h.organizationService.GetOrganizationByID(ctx, organizationID)
	if organizationResponse.HasErrors() {
		errorResp := organizationResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::GetOrganization -> Failed to get organization from service")
	}

	util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::GetOrganization")
}

func (h *OrganizationHandler) ListOrganizations(c *gin.Context) {
	ctx := c.Request.Context()

	req := &contract.ListOrganizationsRequest{
		Page:  1,
		Limit: 10,
	}

	// Parse query parameters
	if pageStr := c.Query("page"); pageStr != "" {
		if page, err := strconv.Atoi(pageStr); err == nil {
			req.Page = page
		}
	}

	if limitStr := c.Query("limit"); limitStr != "" {
		if limit, err := strconv.Atoi(limitStr); err == nil {
			req.Limit = limit
		}
	}

	if search := c.Query("search"); search != "" {
		req.Search = search
	}

	if planType := c.Query("plan_type"); planType != "" {
		req.PlanType = planType
	}

	validationError, validationErrorCode := h.organizationValidator.ValidateListOrganizationsRequest(req)
	if validationError != nil {
		logger.FromContext(ctx).WithError(validationError).Error("OrganizationHandler::ListOrganizations -> request validation failed")
		validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::ListOrganizations")
		return
	}

	organizationsResponse := h.organizationService.ListOrganizations(ctx, req)
	if organizationsResponse.HasErrors() {
		errorResp := organizationsResponse.GetErrors()[0]
		logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::ListOrganizations -> Failed to list organizations from service")
	}

	util.HandleResponse(c.Writer, c.Request, organizationsResponse, "OrganizationHandler::ListOrganizations")
}

// Old error response methods removed - now using util.HandleResponse pattern
