package com.braintree.graphql.commands.impl;

import com.braintree.command.result.BrainTreeTransactionResult;
import com.braintree.commands.BrainTreeFindTransactionByIdCommand;
import com.braintree.commands.impl.AbstractCommand;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import com.google.gson.Gson;
import de.hybris.platform.payment.AdapterException;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import org.apache.log4j.Logger;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.braintree.constants.BraintreeConstants.ID_PARAMETER;
import static com.braintree.constants.BraintreeConstants.RESULT_DATA;
import static com.braintree.constants.BraintreeConstants.RESULT_ERRORS;

public class DefaultBrainTreeGraphQLGetTransactionByIdCommand extends
        AbstractCommand<String, BrainTreeTransactionResult> implements BrainTreeFindTransactionByIdCommand {

    private static final Logger LOG = Logger.getLogger(DefaultBrainTreeGraphQLGetTransactionByIdCommand.class);

    private static final String DEFINITION_FILE_NAME = "searchTransactionById";
    private static final String NODE = "node";

    @Resource(name = "braintreeTransactionToBraintreeTransactionResultConverter")
    private Converter<BrainTreeTransaction, BrainTreeTransactionResult> transactionResultConverter;

    @Override
    public BrainTreeTransactionResult perform(String transactionId) {
        try {
            Map<String, Object> result = makeGraphQlCall(DEFINITION_FILE_NAME, createVariablesMap(transactionId));

            ArrayList<Map<String, Object>> mapErrors = (ArrayList<Map<String, Object>>) result.get(RESULT_ERRORS);

            if (mapErrors == null) {
                return translateResponse((Map<String, Object>) result.get(RESULT_DATA));
            } else {
                String message = "[BT get transaction by id method] Error due getting transaction. " + getFistErrorMessage(
                        mapErrors);
                LOG.error(message);
                throw new AdapterException(message);
            }

        } catch (Exception ex) {
            throw new AdapterException(ex.getMessage(), ex);
        }
    }

    private Map<String, Object> createVariablesMap(String transactionId) {
        Map<String, Object> map = new HashMap<>();
        map.put(ID_PARAMETER, transactionId);
        return map;
    }

    private BrainTreeTransactionResult translateResponse(Map<String, Object> data) {
        BrainTreeTransaction transaction = objectMapper
                .convertValue(data.get(NODE), BrainTreeTransaction.class);
        LOG.info("Found transaction by id: " + new Gson().toJson(transaction));

        return transactionResultConverter.convert(transaction);
    }

}
