package com.banesco.module.service_order_payment_search.infrastructure.mapper;

import com.banesco.module.document.domain.model.Document;
import com.banesco.module.party.domain.model.Party;
import com.banesco.module.party.domain.model.PartyIdentification;
import com.banesco.module.payment_order.domain.dto.request.PaymentOrderRequest;
import com.banesco.module.payment_order.domain.model.Operation;
import com.banesco.module.payment_order.domain.model.PaymentOrderBol;
import com.banesco.module.payment_order.domain.model.PaymentOrderBole;
import com.banesco.module.service_order_payment_search.domain.dto.request.ServiceOrderPaymentSearchRequest;
import com.banesco.module.service_order_payment_search.domain.model.ServicingOrderProcedure;
import com.banesco.common.domain.model.Identifier;
import com.banesco.module.transaction.domain.model.*;
import io.netty.util.internal.StringUtil;

import java.util.List;

public class ServicingOrderMapper {

    private ServicingOrderMapper() {}

    public static PaymentOrderRequest toPaymentRequest(
        ServiceOrderPaymentSearchRequest request
    ) {
        return PaymentOrderRequest.builder()
            .fintechId(request.getCustomerReferenceFintechId())
            .operation(
                Operation.builder()
                    .recipientId(request.getPartyId())
                    .dateCreate((!StringUtil.isNullOrEmpty(request.getInitiatedDate()))
                        ? request.getInitiatedDate()
                        : null
                    )
                    .id((!StringUtil.isNullOrEmpty(request.getInstructionRequestId()))
                        ? Long.valueOf(request.getInstructionRequestId())
                        : null
                    )
                    .build()
            )
            .channelId(request.getChannelCode())
            .build();
    }

    public static List<ServicingOrderProcedure> toBoleModel(List<PaymentOrderBole> response) {
        return response.stream().map(paymentOrderBole ->
            ServicingOrderProcedure.builder()
                .document(buildDocumentProduct(paymentOrderBole))
                .transaction(buildBoleTransaction(paymentOrderBole))
                .build()
        ).toList();
    }

    public static List<ServicingOrderProcedure> toBolModel(List<PaymentOrderBol> response) {
        return response.stream().map(paymentOrderBole ->
            ServicingOrderProcedure.builder()
                .transaction(buildBolTransaction(paymentOrderBole))
                .build()
        ).toList();
    }

    private static Document buildDocumentProduct(PaymentOrderBole paymentOrderBole) {
        return Document.builder()
            .documentName(paymentOrderBole.getFileName())
            .build();
    }

    private static Transaction buildBoleTransaction(PaymentOrderBole paymentOrderBole) {
        return Transaction.builder()
            .transactionIdentification(Identifier.builder()
                .identifierValue(String.valueOf(paymentOrderBole.getNroRequest()))
                .build())
            .transactionStatus(buildBoleTransactionStatus(paymentOrderBole))
            .transactionDate(buildBoleTransactionDateTimeList(paymentOrderBole))
            .transactionDetails(TransactionDetails.builder()
                .transactionQuantity(paymentOrderBole.getQuantity())
                .build())
            .build();
    }

    private static Transaction buildBolTransaction(PaymentOrderBol paymentOrderBol) {
        return Transaction.builder()
            .transactionIdentification(Identifier.builder()
                .identifierValue(String.valueOf(paymentOrderBol.getId()))
                .build())
            .transactionStatus(buildBolTransactionStatus(paymentOrderBol))
            .transactionDate(buildBolTransactionDateTimeList(paymentOrderBol))
            .transactionInvolvement(buildBolTransactionInvolvement(paymentOrderBol))
            .financialTransaction(buildBolFinancialTransaction(paymentOrderBol))
            .name(paymentOrderBol.getRequestType())
            .description(paymentOrderBol.getConcept())
            .build();
    }

    private static TransactionStatus buildBoleTransactionStatus(PaymentOrderBole paymentOrderBole) {
        return TransactionStatus.builder()
            .statusType(mapTransactionStatusType(paymentOrderBole.getStatus()))
            .statusName(paymentOrderBole.getStatus())
            .statusAccepted(paymentOrderBole.getAccepted())
            .statusRejected(paymentOrderBole.getRejected())
            .statusExpired(paymentOrderBole.getExpired())
            .build();
    }

    private static TransactionStatus buildBolTransactionStatus(PaymentOrderBol paymentOrderBol) {
        return TransactionStatus.builder()
            .statusType(mapTransactionStatusType(paymentOrderBol.getStatus()))
            .statusName(paymentOrderBol.getStatus())
            .build();
    }

    private static List<TransactionDateTime> buildBoleTransactionDateTimeList(PaymentOrderBole paymentOrderBole) {
        return List.of(
            TransactionDateTime.builder()
                .dateType(TransactionDateTimeType.EXECUTED_DATE)
                .date(paymentOrderBole.getDispatchDate())
                .build()
        );
    }

    private static List<TransactionDateTime> buildBolTransactionDateTimeList(PaymentOrderBol paymentOrderBol) {
        return List.of(
            TransactionDateTime.builder()
                .dateType(TransactionDateTimeType.INITIATED_DATE)
                .date(paymentOrderBol.getDateCreate())
                .build()
        );
    }

    private static List<TransactionInvolvement> buildBolTransactionInvolvement(PaymentOrderBol paymentOrderBol) {
        return List.of(
            TransactionInvolvement.builder()
                .partyReference(
                    Party.builder()
                        .partyIdentification(List.of(
                            PartyIdentification.builder()
                                .partyIdentification(
                                    Identifier.builder()
                                        .identifierValue(paymentOrderBol.getEmitterReceptor())
                                        .build()
                                )
                                .build()
                        ))
                        .build()
                )
                .build()
        );
    }

    private static FinancialTransaction buildBolFinancialTransaction(PaymentOrderBol paymentOrderBol) {
        return FinancialTransaction.builder()
            .amount(paymentOrderBol.getAmount())
            .currencyCode(paymentOrderBol.getCurrency())
            .build();
    }

    private static TransactionStatusType mapTransactionStatusType(String codeStatusRequest) {
        if (codeStatusRequest == null) {
            return TransactionStatusType.PENDING;
        }

        return switch (codeStatusRequest.toUpperCase()) {
            case "ACT", "ACTIVO", "ACTIVA" -> TransactionStatusType.ACTIVE;
            case "PENDIENTE" -> TransactionStatusType.PENDING;
            case "EXITO", "EXITOSA", "COMPLETADO", "FINALIZADO" -> TransactionStatusType.COMPLETED;
            case "APROBADO", "APROBADA" -> TransactionStatusType.APPROVED;
            case "CONF", "CONFIRMADO", "CONFIRMADA" -> TransactionStatusType.CONFIRMED;
            case "INICIADO" -> TransactionStatusType.INITIATED;
            case "EN_PROCESO", "PROCESANDO", "EN CURSO" -> TransactionStatusType.IN_PROGRESS;
            case "RECH", "RECHAZADO", "FALLA", "FALLIDO", "RECHAZADA", "FALLIDA" -> TransactionStatusType.REJECTED;
            case "CANCELADO" -> TransactionStatusType.CANCELLED;
            case "SUSPENDIDO" -> TransactionStatusType.SUSPENDED;
            case "NOTIFICADO" -> TransactionStatusType.NOTIFIED;
            case "CONTABILIZADO" -> TransactionStatusType.BOOKED;
            case "EJECUTADO" -> TransactionStatusType.EXECUTED;
            case "EXP", "EXPIRADO", "EXPIRADA" -> TransactionStatusType.EXPIRED;
            case "ENVIADO", "ENVIADA" -> TransactionStatusType.SENT;
            case "RECIBIDO", "RECIBIDA" -> TransactionStatusType.RECEIVED;
            case "LEIDA" -> TransactionStatusType.READ;
            case "PROG", "PROGRAMADO", "PROGRAMADA" -> TransactionStatusType.PROGRAMED;
            case "TRANSATIP" -> TransactionStatusType.ATYPICAL_TRANSACTION;
            default -> TransactionStatusType.DEFAULT;
        };
    }
}