package com.braintree.graphql.commands.impl;

import com.braintree.command.result.BrainTreePaymentDetailsResult;
import com.braintree.commands.BrainTreeGetPaymentMethodByTokenCommand;
import com.braintree.commands.impl.AbstractCommand;
import com.braintree.hybris.data.graphql.commands.response.BraintreePaymentMethodData;
import com.braintree.method.BrainTreePaymentService;
import com.braintree.payment.info.service.BraintreePaymentInfoService;
import de.hybris.platform.payment.AdapterException;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import org.apache.log4j.Logger;

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;

/**
 * This class extends AbstractCommand, implements BrainTreeGetPaymentMethodByTokenCommand and is used in GraphQL API.
 */
public class DefaultBrainTreeGraphQLGetPaymentMethodByTokenCommand extends
        AbstractCommand<String, BrainTreePaymentDetailsResult> implements BrainTreeGetPaymentMethodByTokenCommand {

    private static final String DEFINITION_FILE_NAME = "node";

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

    private BrainTreePaymentService brainTreePaymentService;
    private BraintreePaymentInfoService paymentInfoService;
    private Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> graphQLPaymentMethodToPaymentDetailsConverter;

    @Override
    public BrainTreePaymentDetailsResult perform(final String paymentMethodToken) {
        try {
            Map<String, Object> result = makeGraphQlCall(DEFINITION_FILE_NAME, createVariablesMap(paymentMethodToken));
            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 payment method] Error due getting payment method. " + getFistErrorMessage(
                        mapErrors);
                LOG.error(message);
                throw new AdapterException(message);
            }
        } catch (Exception ex) {
            throw new AdapterException(ex.getMessage(), ex);
        }
    }

    private BrainTreePaymentDetailsResult translateResponse(Map<String, Object> data) {
        BraintreePaymentMethodData payload = objectMapper
                .convertValue(data.get(DEFINITION_FILE_NAME), BraintreePaymentMethodData.class);
        return graphQLPaymentMethodToPaymentDetailsConverter.convert(payload);
    }

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

    public BrainTreePaymentService getBrainTreePaymentService() {
        return brainTreePaymentService;
    }

    public void setBrainTreePaymentService(BrainTreePaymentService brainTreePaymentService) {
        this.brainTreePaymentService = brainTreePaymentService;
    }

    public BraintreePaymentInfoService getPaymentInfoService() {
        return paymentInfoService;
    }

    public void setPaymentInfoService(BraintreePaymentInfoService paymentInfoService) {
        this.paymentInfoService = paymentInfoService;
    }

    public Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> getGraphQLPaymentMethodToPaymentDetailsConverter() {
        return graphQLPaymentMethodToPaymentDetailsConverter;
    }

    public void setGraphQLPaymentMethodToPaymentDetailsConverter(
            Converter<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> graphQLPaymentMethodToPaymentDetailsConverter) {
        this.graphQLPaymentMethodToPaymentDetailsConverter = graphQLPaymentMethodToPaymentDetailsConverter;
    }

}
