package service

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/processor"
	"apskel-pos-be/internal/transformer"
	"context"

	"github.com/google/uuid"
)

type IngredientUnitConverterService interface {
	CreateIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateIngredientUnitConverterRequest) *contract.Response
	UpdateIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateIngredientUnitConverterRequest) *contract.Response
	DeleteIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
	GetIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
	ListIngredientUnitConverters(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListIngredientUnitConvertersRequest) *contract.Response
	GetConvertersForIngredient(ctx context.Context, apctx *appcontext.ContextInfo, ingredientID uuid.UUID) *contract.Response
	ConvertUnit(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ConvertUnitRequest) *contract.Response
}

type IngredientUnitConverterServiceImpl struct {
	converterProcessor processor.IngredientUnitConverterProcessor
}

func NewIngredientUnitConverterService(converterProcessor processor.IngredientUnitConverterProcessor) *IngredientUnitConverterServiceImpl {
	return &IngredientUnitConverterServiceImpl{
		converterProcessor: converterProcessor,
	}
}

func (s *IngredientUnitConverterServiceImpl) CreateIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateIngredientUnitConverterRequest) *contract.Response {
	modelReq := transformer.CreateIngredientUnitConverterRequestToModel(req)

	converterResponse, err := s.converterProcessor.CreateIngredientUnitConverter(ctx, apctx.OrganizationID, apctx.UserID, modelReq)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.IngredientUnitConverterModelResponseToResponse(converterResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

func (s *IngredientUnitConverterServiceImpl) UpdateIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateIngredientUnitConverterRequest) *contract.Response {
	modelReq := transformer.UpdateIngredientUnitConverterRequestToModel(req)

	converterResponse, err := s.converterProcessor.UpdateIngredientUnitConverter(ctx, id, apctx.OrganizationID, apctx.UserID, modelReq)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.IngredientUnitConverterModelResponseToResponse(converterResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

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

	return contract.BuildSuccessResponse(nil)
}

func (s *IngredientUnitConverterServiceImpl) GetIngredientUnitConverter(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
	converterResponse, err := s.converterProcessor.GetIngredientUnitConverterByID(ctx, id, apctx.OrganizationID)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.IngredientUnitConverterModelResponseToResponse(converterResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

func (s *IngredientUnitConverterServiceImpl) ListIngredientUnitConverters(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListIngredientUnitConvertersRequest) *contract.Response {
	modelReq := transformer.ListIngredientUnitConvertersRequestToModel(req)

	filters := make(map[string]interface{})
	if modelReq.IngredientID != nil {
		filters["ingredient_id"] = *modelReq.IngredientID
	}
	if modelReq.FromUnitID != nil {
		filters["from_unit_id"] = *modelReq.FromUnitID
	}
	if modelReq.ToUnitID != nil {
		filters["to_unit_id"] = *modelReq.ToUnitID
	}
	if modelReq.IsActive != nil {
		filters["is_active"] = *modelReq.IsActive
	}
	if modelReq.Search != "" {
		filters["search"] = modelReq.Search
	}

	converters, total, err := s.converterProcessor.ListIngredientUnitConverters(ctx, apctx.OrganizationID, filters, modelReq.Page, modelReq.Limit)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponses := make([]contract.IngredientUnitConverterResponse, len(converters))
	for i, converter := range converters {
		contractResponses[i] = transformer.IngredientUnitConverterModelResponseToResponse(converter)
	}

	totalPages := (total + modelReq.Limit - 1) / modelReq.Limit
	response := contract.ListIngredientUnitConvertersResponse{
		Converters: contractResponses,
		TotalCount: total,
		Page:       modelReq.Page,
		Limit:      modelReq.Limit,
		TotalPages: totalPages,
	}

	return contract.BuildSuccessResponse(response)
}

func (s *IngredientUnitConverterServiceImpl) GetConvertersForIngredient(ctx context.Context, apctx *appcontext.ContextInfo, ingredientID uuid.UUID) *contract.Response {
	converters, err := s.converterProcessor.GetConvertersForIngredient(ctx, ingredientID, apctx.OrganizationID)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponses := make([]contract.IngredientUnitConverterResponse, len(converters))
	for i, converter := range converters {
		contractResponses[i] = transformer.IngredientUnitConverterModelResponseToResponse(converter)
	}

	return contract.BuildSuccessResponse(contractResponses)
}

func (s *IngredientUnitConverterServiceImpl) ConvertUnit(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ConvertUnitRequest) *contract.Response {
	modelReq := transformer.ConvertUnitRequestToModel(req)

	convertResponse, err := s.converterProcessor.ConvertUnit(ctx, apctx.OrganizationID, modelReq)
	if err != nil {
		errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.IngredientUnitConverterServiceEntity, err.Error())
		return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
	}

	contractResponse := transformer.ConvertUnitModelResponseToResponse(convertResponse)
	return contract.BuildSuccessResponse(contractResponse)
}

