package service

import (
	"apskel-pos-be/internal/appcontext"
	"context"

	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/processor"
	"apskel-pos-be/internal/transformer"

	"github.com/google/uuid"
)

type PurchaseOrderService interface {
	CreatePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreatePurchaseOrderRequest) *contract.Response
	UpdatePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdatePurchaseOrderRequest) *contract.Response
	DeletePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
	GetPurchaseOrderByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
	ListPurchaseOrders(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListPurchaseOrdersRequest) *contract.Response
	GetPurchaseOrdersByStatus(ctx context.Context, apctx *appcontext.ContextInfo, status string) *contract.Response
	GetOverduePurchaseOrders(ctx context.Context, apctx *appcontext.ContextInfo) *contract.Response
	UpdatePurchaseOrderStatus(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, status string) *contract.Response
}

type PurchaseOrderServiceImpl struct {
	purchaseOrderProcessor processor.PurchaseOrderProcessor
}

func NewPurchaseOrderService(purchaseOrderProcessor processor.PurchaseOrderProcessor) *PurchaseOrderServiceImpl {
	return &PurchaseOrderServiceImpl{
		purchaseOrderProcessor: purchaseOrderProcessor,
	}
}

func (s *PurchaseOrderServiceImpl) CreatePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreatePurchaseOrderRequest) *contract.Response {
	modelReq := transformer.CreatePurchaseOrderRequestToModel(req)

	poResponse, err := s.purchaseOrderProcessor.CreatePurchaseOrder(ctx, apctx.OrganizationID, modelReq)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.PurchaseOrderModelResponseToResponse(poResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

func (s *PurchaseOrderServiceImpl) UpdatePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdatePurchaseOrderRequest) *contract.Response {
	modelReq := transformer.UpdatePurchaseOrderRequestToModel(req)

	poResponse, err := s.purchaseOrderProcessor.UpdatePurchaseOrder(ctx, id, apctx.OrganizationID, modelReq)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.PurchaseOrderModelResponseToResponse(poResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

func (s *PurchaseOrderServiceImpl) DeletePurchaseOrder(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
	err := s.purchaseOrderProcessor.DeletePurchaseOrder(ctx, id, apctx.OrganizationID)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	return contract.BuildSuccessResponse(map[string]interface{}{
		"message": "Purchase order deleted successfully",
	})
}

func (s *PurchaseOrderServiceImpl) GetPurchaseOrderByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
	poResponse, err := s.purchaseOrderProcessor.GetPurchaseOrderByID(ctx, id, apctx.OrganizationID)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.PurchaseOrderModelResponseToResponse(poResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

func (s *PurchaseOrderServiceImpl) ListPurchaseOrders(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListPurchaseOrdersRequest) *contract.Response {
	modelReq := transformer.ListPurchaseOrdersRequestToModel(req)

	filters := make(map[string]interface{})
	if modelReq.Search != "" {
		filters["search"] = modelReq.Search
	}
	if modelReq.Status != "" {
		filters["status"] = modelReq.Status
	}
	if modelReq.VendorID != nil {
		filters["vendor_id"] = *modelReq.VendorID
	}
	if modelReq.StartDate != nil {
		filters["start_date"] = *modelReq.StartDate
	}
	if modelReq.EndDate != nil {
		filters["end_date"] = *modelReq.EndDate
	}

	pos, totalPages, err := s.purchaseOrderProcessor.ListPurchaseOrders(ctx, apctx.OrganizationID, filters, modelReq.Page, modelReq.Limit)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponses := make([]contract.PurchaseOrderResponse, len(pos))
	for i, po := range pos {
		response := transformer.PurchaseOrderModelResponseToResponse(po)
		if response != nil {
			contractResponses[i] = *response
		}
	}

	response := contract.ListPurchaseOrdersResponse{
		PurchaseOrders: contractResponses,
		TotalCount:     len(contractResponses),
		Page:           modelReq.Page,
		Limit:          modelReq.Limit,
		TotalPages:     totalPages,
	}

	return contract.BuildSuccessResponse(response)
}

func (s *PurchaseOrderServiceImpl) GetPurchaseOrdersByStatus(ctx context.Context, apctx *appcontext.ContextInfo, status string) *contract.Response {
	poResponses, err := s.purchaseOrderProcessor.GetPurchaseOrdersByStatus(ctx, apctx.OrganizationID, status)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponses := make([]contract.PurchaseOrderResponse, len(poResponses))
	for i, po := range poResponses {
		response := transformer.PurchaseOrderModelResponseToResponse(po)
		if response != nil {
			contractResponses[i] = *response
		}
	}

	return contract.BuildSuccessResponse(contractResponses)
}

func (s *PurchaseOrderServiceImpl) GetOverduePurchaseOrders(ctx context.Context, apctx *appcontext.ContextInfo) *contract.Response {
	poResponses, err := s.purchaseOrderProcessor.GetOverduePurchaseOrders(ctx, apctx.OrganizationID)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponses := make([]contract.PurchaseOrderResponse, len(poResponses))
	for i, po := range poResponses {
		response := transformer.PurchaseOrderModelResponseToResponse(po)
		if response != nil {
			contractResponses[i] = *response
		}
	}

	return contract.BuildSuccessResponse(contractResponses)
}

func (s *PurchaseOrderServiceImpl) UpdatePurchaseOrderStatus(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, status string) *contract.Response {
	poResponse, err := s.purchaseOrderProcessor.UpdatePurchaseOrderStatus(ctx, id, apctx.OrganizationID, apctx.UserID, apctx.OutletID, status)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.PurchaseOrderServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.PurchaseOrderModelResponseToResponse(poResponse)
	return contract.BuildSuccessResponse(contractResponse)
}
