package com.banesco.common.application.helper;

import com.banesco.common.domain.exception.HttpStatusCodeException;
import com.banesco.common.infrastructure.config.RequestValidationConfig;
import com.banesco.module.payment_instruction_request.domain.dto.request.PaymentInstructionRequestRequest;
import com.banesco.module.payment_instruction_request.domain.model.PaymentArrangement;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.List;

@Slf4j
@ApplicationScoped
public class RequestValidatorHelper {
    private final RequestValidationConfig config;

    private static final String REQUIRED_CODE = "VDE01";
    private static final String VALIDATE_CODE = "VDE02";

    @Inject
    public RequestValidatorHelper(
        RequestValidationConfig config
    ) {
        this.config = config;
    }

    public void validateRequired(
        PaymentInstructionRequestRequest request
    ) {
        required(request.getRecipientId(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.arrangement[0].arrangementInvolvement[0].partyReference.partyIdentification[IDENTITY_CARD_NUMBER].partyIdentification.identifierValue");
        required(request.getRecipientPhone(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.arrangement[0].arrangementInvolvement[0].partyReference.partyIdentification[TELEPHONE_NUMBER].partyIdentification.identifierValue");
        required(request.getBankCode(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.bankingProduct.productName");
        required(request.getAmount(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.paymentAmount");
        required(request.getPurpose(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.paymentPurpose");
        required(request.getEffectiveDate(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.paymentDate[0].date");

        required(request.getPaymentArrangement(), "paymentInstructionTransaction.paymentArrangement");

        int index = 0;

        for (PaymentArrangement item: request.getPaymentArrangement()) {
            required(item.getApplicantId(), "paymentInstructionTransaction.paymentArrangement[%d].arrangement[0].arrangementInvolvement[PARTY_IS_OBLIGOR_IN_ARRANGEMENT].partyReference.partyIdentification[IDENTITY_CARD_NUMBER].partyIdentification.identifierValue".formatted(index));
            required(item.getApplicantPhone(), "paymentInstructionTransaction.paymentArrangement[%d].arrangement[0].arrangementInvolvement[PARTY_IS_OBLIGOR_IN_ARRANGEMENT].partyReference.partyIdentification[TELEPHONE_NUMBER].partyIdentification.identifierValue".formatted(index));

            required(item.getAmount(), "paymentInstructionTransaction.paymentArrangement[%d].paymentAmount".formatted(index));
            required(item.getPurpose(), "paymentInstructionTransaction.paymentArrangement[%d].paymentPurpose".formatted(index));
            required(item.getEffectiveDate(), "paymentInstructionTransaction.paymentArrangement[%d].paymentDate[0].date".formatted(index));

            index++;
        }

        required(request.getChannelCode(), "procedureRequest.instructionPurposeType");
        required(request.getCustomerReferenceFintechId(), "customerReferenceFintechId");
        required(request.getAppId(), "appId");
    }

    public void validateFieldValues(
        PaymentInstructionRequestRequest request
    ) {
        validate(request.getRecipientId(), config.recipientIdNumber(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.arrangement[0].arrangementInvolvement[0].partyReference.partyIdentification[IDENTITY_CARD_NUMBER].partyIdentification.identifierValue");
        validate(request.getRecipientPhone(), config.recipientPhoneNumber(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.arrangement[0].arrangementInvolvement[0].partyReference.partyIdentification[TELEPHONE_NUMBER].partyIdentification.identifierValue");
        validate(request.getAmount(), "paymentInstructionTransaction.paymentInstruction.paymentArrangement.amount");

        int index = 0;

        for (PaymentArrangement item: request.getPaymentArrangement()) {
            validate(item.getApplicantId(), config.applicantIdNumber(), "paymentInstructionTransaction.paymentArrangement[%d].arrangement[0].arrangementInvolvement[PARTY_IS_OBLIGOR_IN_ARRANGEMENT].partyReference.partyIdentification[IDENTITY_CARD_NUMBER].partyIdentification.identifierValue".formatted(index));
            validate(item.getApplicantPhone(), config.applicantPhoneNumber(), "paymentInstructionTransaction.paymentArrangement[%d].arrangement[0].arrangementInvolvement[PARTY_IS_OBLIGOR_IN_ARRANGEMENT].partyReference.partyIdentification[TELEPHONE_NUMBER].partyIdentification.identifierValue".formatted(index));

            validate(item.getAmount(), "paymentInstructionTransaction.paymentArrangement[%d].paymentAmount".formatted(index));

            index++;
        }

        validate(request.getChannelCode(), config.channelCode(), "procedureRequest.instructionPurposeType");
    }

    private void required(String value, String fieldName) {
        if (value == null || value.trim().isEmpty()) {
            throw HttpStatusCodeException.badRequest(REQUIRED_CODE, fieldName);
        }
    }

    private void required(BigDecimal value, String fieldName) {
        if (value == null) {
            throw HttpStatusCodeException.badRequest(REQUIRED_CODE, fieldName);
        }
    }

    private void required(List<?> value, String fieldName) {
        if (value == null || value.isEmpty()) {
            throw HttpStatusCodeException.badRequest(REQUIRED_CODE, fieldName);
        }
    }

    private void validate(String value, String regex, String fieldName) {
        if (value != null && !value.isEmpty() && !value.matches(regex)) {
            throw HttpStatusCodeException.badRequest(VALIDATE_CODE, fieldName);
        }
    }

    private void validate(BigDecimal value, String fieldName) {
        if (value != null && value.compareTo(BigDecimal.ZERO) < 1) {
            throw HttpStatusCodeException.badRequest(VALIDATE_CODE, fieldName);
        }
    }
}
