package com.braintree.graphql.commands.impl;

import static com.braintree.constants.BraintreeConstants.INPUT_PARAMETER;
import static com.braintree.constants.BraintreeConstants.RESULT_ERRORS;
import static de.hybris.platform.servicelayer.util.ServicesUtil.validateParameterNotNullStandardMessage;

import com.braintree.command.request.BrainTreeCustomerRequest;
import com.braintree.command.result.BrainTreeCustomerResult;
import com.braintree.commands.BrainTreeRemoveCustomerCommand;
import com.braintree.commands.impl.AbstractCommand;
import com.braintree.customer.service.BrainTreeCustomerAccountService;
import com.braintree.hybris.data.graphql.commands.request.BrainTreeDeleteCustomerInput;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeErrorDefinition;
import com.braintreegateway.exceptions.NotFoundException;
import de.hybris.platform.payment.AdapterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;

/**
 * This class extends AbstractCommand, implements BrainTreeRemoveCustomerCommand and is used in GraphQL API.
 */
public class DefaultBrainTreeGraphQLRemoveCustomerCommand extends AbstractCommand implements
    BrainTreeRemoveCustomerCommand {

    private static final String DEFINITION_FILE_NAME = "deleteCustomer";
    private static final String REMOVE_CUSTOMER_REQUEST_PARAMETER = "Remove customer request";
    private static final String CAN_NOT_BE_DELETE_ERROR_LOG_MESSAGE = "BT customer id(%s) can not be delete error: %s %s";
    private static final String CUSTOMER_WITH_ID_S_NOT_FOUND_ERROR_LOG_MESSAGE = "Customer with id=%s not Found! Error %s";
    private static final String CUSTOMER_WITH_ID_S_NOT_FOUND = "Customer with id=%s not Found!";

    private BrainTreeCustomerAccountService brainTreeCustomerAccountService;

    @Override
    public BrainTreeCustomerResult perform(final BrainTreeCustomerRequest request) {
        validateParameterNotNullStandardMessage(REMOVE_CUSTOMER_REQUEST_PARAMETER, request);
        try {
            Map<String, Object> result = makeGraphQlCall(DEFINITION_FILE_NAME, createVariablesMap(request));
            ArrayList<Map<String, Object>> mapErrors = (ArrayList<Map<String, Object>>) result.get(RESULT_ERRORS);

            if (mapErrors == null) {
                return new BrainTreeCustomerResult(true);
            } else {
                List<BrainTreeErrorDefinition> errors = mapErrors.stream()
                    .map(stringObjectMap -> objectMapper.convertValue(stringObjectMap, BrainTreeErrorDefinition.class))
                    .collect(Collectors.toList());
                return translateErrorResponse(request.getCustomerId(), errors);
            }
        } catch (final NotFoundException notFoundException) {
            return translateNotFoundResponse(request, notFoundException);
        } catch (final Exception exception) {
            throw new AdapterException(exception.getMessage(), exception);
        }
    }

    private BrainTreeCustomerResult translateErrorResponse(final String customerId,
        List<BrainTreeErrorDefinition> errors) {
        final BrainTreeCustomerResult response = new BrainTreeCustomerResult(false);
        if (errors != null && errors.size() > 0) {
            BrainTreeErrorDefinition errorDefinition = errors.get(0);
            getLoggingHandler().getLogger().info(
                String.format(CAN_NOT_BE_DELETE_ERROR_LOG_MESSAGE, customerId,
                    errorDefinition.getExtensions().getLegacyCode(),
                    errorDefinition.getMessage()));

            if (errorDefinition.getExtensions().getLegacyCode() != null) {
                response.setErrorCode(errorDefinition.getExtensions().getLegacyCode());
            }
            response.setErrorMessage(errorDefinition.getMessage());

        }
        return response;
    }

    private BrainTreeCustomerResult translateNotFoundResponse(final BrainTreeCustomerRequest request,
        final NotFoundException notFoundException) {
        getLoggingHandler().getLogger().info(
            String.format(CUSTOMER_WITH_ID_S_NOT_FOUND_ERROR_LOG_MESSAGE, request.getCustomerId(),
                notFoundException.getMessage()));

        final BrainTreeCustomerResult brainTreeCustomerResult = new BrainTreeCustomerResult(
            false);
        brainTreeCustomerResult
            .setErrorMessage(String.format(CUSTOMER_WITH_ID_S_NOT_FOUND, request.getCustomerId()));
        return brainTreeCustomerResult;
    }

    private Map<String, Object> createVariablesMap(final BrainTreeCustomerRequest request) {
        Map<String, Object> map = new HashMap<>();
        BrainTreeDeleteCustomerInput input = new BrainTreeDeleteCustomerInput();
        if (StringUtils.isNotEmpty(request.getCustomerId())) {
            input.setCustomerId(brainTreeCustomerAccountService.getGraphQLIdForCustomer(request.getCustomerId()));
        }
        map.put(INPUT_PARAMETER, input);
        return map;
    }

    public BrainTreeCustomerAccountService getBrainTreeCustomerAccountService() {
        return brainTreeCustomerAccountService;
    }

    public void setBrainTreeCustomerAccountService(
        BrainTreeCustomerAccountService brainTreeCustomerAccountService) {
        this.brainTreeCustomerAccountService = brainTreeCustomerAccountService;
    }
}
