package com.braintree.payment.info.dao.impl;

import com.braintree.enums.BrainTreePaymentMethod;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.braintree.payment.info.dao.BrainTreePaymentInfoDao;
import de.hybris.platform.core.servicelayer.data.SearchPageData;
import de.hybris.platform.servicelayer.internal.dao.AbstractItemDao;
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.SearchResult;
import de.hybris.platform.servicelayer.search.paginated.PaginatedFlexibleSearchParameter;
import de.hybris.platform.servicelayer.search.paginated.PaginatedFlexibleSearchService;
import de.hybris.platform.servicelayer.util.ServicesUtil;

import java.util.*;


public class DefaultBrainTreePaymentInfoDao extends AbstractItemDao implements BrainTreePaymentInfoDao {

    public static final String DUPLICATE = "duplicate";
    public static final String CUSTOMER_ID = "customerId";
    public static final String CODE = "code";
    public static final String TYPE = "type";
    public static final String SAVED = "saved";
    public static final String IS_DELETED_ON_BRAINTREE = "isDeletedOnBraintree";
    public static final String PAYMENT_METHOD_TOKEN = "paymentMethodToken";

    private PaginatedFlexibleSearchService paginatedFlexibleSearchService;

    private static final String GET_PAYMENT_INFO_MODEL_BY_CUSTOMER_ID_AND_PAYMENT_METHOD_TOKEN_QUERY = "SELECT {"
            + BrainTreePaymentInfoModel.PK + "} FROM {" + BrainTreePaymentInfoModel._TYPECODE + "} WHERE {"
            + BrainTreePaymentInfoModel.CUSTOMERID + "}=?" + CUSTOMER_ID + " AND {"
            + BrainTreePaymentInfoModel.PAYMENTMETHODTOKEN + "}=?" + PAYMENT_METHOD_TOKEN + " AND {"
            + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE;

    private static final String GET_PAYMENT_INFO_MODEL_BY_CUSTOMER_ID_CODE_QUERY = "SELECT {"
        + BrainTreePaymentInfoModel.PK + "} FROM {" + BrainTreePaymentInfoModel._TYPECODE + "} WHERE {"
        + BrainTreePaymentInfoModel.CUSTOMERID + "}=?" + CUSTOMER_ID + " AND {"
        + BrainTreePaymentInfoModel.PK + "}=?" + CODE + " AND {"
        + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE;

    private static final String GET_PAYMENT_INFO_MODEL_BY_PAYMENT_METHOD_TOKEN_QUERY = "SELECT {"
            + BrainTreePaymentInfoModel.PK + "} FROM {" + BrainTreePaymentInfoModel._TYPECODE + "} WHERE {"
            + BrainTreePaymentInfoModel.PAYMENTMETHODTOKEN +"}=?" + PAYMENT_METHOD_TOKEN + " AND {"
            + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE;

    public static final String GET_CREDIT_CARD_PAYMENT_INFO_MODELS = "SELECT {"
            + BrainTreePaymentInfoModel.PK + "} FROM {" + BrainTreePaymentInfoModel._TYPECODE + "}" +" WHERE {"
            + BrainTreePaymentInfoModel.PAYMENTPROVIDER + "}=?" + TYPE + " AND {"
            + BrainTreePaymentInfoModel.SAVED + "}=?"+ SAVED + " AND {"
            + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE + " AND {"
            + BrainTreePaymentInfoModel.ISDELETEDONBRAINTREE + "}=?" + IS_DELETED_ON_BRAINTREE;

    private static final String GET_CREDIT_CARD_PAYMENT_INFO_MODELS_FOR_CUSTOMER = "SELECT {"
            + BrainTreePaymentInfoModel.PK + "} FROM {" + BrainTreePaymentInfoModel._TYPECODE + "}" +" WHERE {"
            + BrainTreePaymentInfoModel.PAYMENTPROVIDER + "}=?" + TYPE + " AND {"
            + BrainTreePaymentInfoModel.SAVED + "}=?"+ SAVED + " AND {"
            + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE + " AND {"
            + BrainTreePaymentInfoModel.CUSTOMERID + "}=?" + CUSTOMER_ID + " AND {"
            + BrainTreePaymentInfoModel.ISDELETEDONBRAINTREE + "}=?" + IS_DELETED_ON_BRAINTREE;

    public static final String GET_PAYMENT_INFO_COUNT_BY_CUSTOMER_AND_PAYMENT_PROVIDER = "SELECT COUNT({"
            + BrainTreePaymentInfoModel.PK + "}) FROM {" + BrainTreePaymentInfoModel._TYPECODE + "}" +" WHERE {"
            + BrainTreePaymentInfoModel.PAYMENTPROVIDER + "}=?" + TYPE + " AND {"
            + BrainTreePaymentInfoModel.SAVED + "}=?"+ SAVED + " AND {"
            + BrainTreePaymentInfoModel.DUPLICATE + "}=?" + DUPLICATE + " AND {"
            + BrainTreePaymentInfoModel.CUSTOMERID + "}=?" + CUSTOMER_ID;

    @Override
    public BrainTreePaymentInfoModel find(final String customerId, final String paymentMethodToken) {
        ServicesUtil.validateParameterNotNull(customerId, "customerId must not be null");
        ServicesUtil.validateParameterNotNull(paymentMethodToken, "paymentMethodToken must not be null");
        final Map queryParams = new HashMap();
        queryParams.put(CUSTOMER_ID, customerId);
        queryParams.put(PAYMENT_METHOD_TOKEN, paymentMethodToken);
        queryParams.put(DUPLICATE, Boolean.FALSE);

        final SearchResult result = getFlexibleSearchService().search(
                GET_PAYMENT_INFO_MODEL_BY_CUSTOMER_ID_AND_PAYMENT_METHOD_TOKEN_QUERY, queryParams);

        return ((result.getCount() > 0) ? (BrainTreePaymentInfoModel) result.getResult().get(0) : null);
    }

    @Override
    public Optional<BrainTreePaymentInfoModel> findByCustomerIdAndCode(String customerId, String code) {
        ServicesUtil.validateParameterNotNull(customerId, "customerId must not be null");
        ServicesUtil.validateParameterNotNull(code, "code must not be null");
        final Map queryParams = new HashMap();
        queryParams.put(CUSTOMER_ID, customerId);
        queryParams.put(CODE, code);
        queryParams.put(DUPLICATE, Boolean.FALSE);

        final SearchResult<BrainTreePaymentInfoModel> result = getFlexibleSearchService().<BrainTreePaymentInfoModel>search(
            GET_PAYMENT_INFO_MODEL_BY_CUSTOMER_ID_CODE_QUERY, queryParams);

        return (result.getCount() > 0) ? Optional.ofNullable(result.getResult().get(0)) : Optional.empty();
    }

    @Override
    public BrainTreePaymentInfoModel find(final String paymentMethodToken) {
        ServicesUtil.validateParameterNotNull(paymentMethodToken, "paymentMethodToken must not be null");
        final Map queryParams = new HashMap();
        queryParams.put(PAYMENT_METHOD_TOKEN, paymentMethodToken);
        queryParams.put(DUPLICATE, Boolean.FALSE);

        final SearchResult result = getFlexibleSearchService().search(
                GET_PAYMENT_INFO_MODEL_BY_PAYMENT_METHOD_TOKEN_QUERY, queryParams);

        return ((result.getCount() > 0) ? (BrainTreePaymentInfoModel) result.getResult().get(0) : null);
    }

    @Override
    public SearchPageData<BrainTreePaymentInfoModel> findAllSavedCreditCard(
            SearchPageData<BrainTreePaymentInfoModel> searchPageData) {
        final Map queryParams = new HashMap();
        queryParams.put(TYPE, BrainTreePaymentMethod.CREDITCARD.getCode());
        queryParams.put(SAVED, Boolean.TRUE);
        queryParams.put(DUPLICATE, Boolean.FALSE);
        queryParams.put(IS_DELETED_ON_BRAINTREE, Boolean.FALSE);

        PaginatedFlexibleSearchParameter paginatedFlexibleSearchParameter = new PaginatedFlexibleSearchParameter();

        paginatedFlexibleSearchParameter.setFlexibleSearchQuery(
                new FlexibleSearchQuery(GET_CREDIT_CARD_PAYMENT_INFO_MODELS, queryParams));
        paginatedFlexibleSearchParameter.setSearchPageData(searchPageData);

        return getPaginatedFlexibleSearchService().search(paginatedFlexibleSearchParameter);
    }

    @Override
    public List<BrainTreePaymentInfoModel> findAllSavedCreditCardByCustomer(String customerId) {
        final Map queryParams = new HashMap();
        queryParams.put(TYPE, BrainTreePaymentMethod.CREDITCARD.getCode());
        queryParams.put(SAVED, Boolean.TRUE);
        queryParams.put(DUPLICATE, Boolean.FALSE);
        queryParams.put(CUSTOMER_ID, customerId);
        queryParams.put(IS_DELETED_ON_BRAINTREE, Boolean.FALSE);

        return getFlexibleSearchService().<BrainTreePaymentInfoModel>search(
                new FlexibleSearchQuery(GET_CREDIT_CARD_PAYMENT_INFO_MODELS_FOR_CUSTOMER, queryParams)).getResult();
    }

    @Override
    public int countPaymentInfoByCustomerIdAndPaymentProvider(String customerId, BrainTreePaymentMethod paymentProvider) {
        final Map<String, Object> queryParams = new HashMap<>();
        queryParams.put(TYPE, paymentProvider.getCode());
        queryParams.put(SAVED, Boolean.TRUE);
        queryParams.put(DUPLICATE, Boolean.FALSE);
        queryParams.put(CUSTOMER_ID, customerId);

        FlexibleSearchQuery flexibleSearchQuery = new FlexibleSearchQuery(GET_PAYMENT_INFO_COUNT_BY_CUSTOMER_AND_PAYMENT_PROVIDER, queryParams);
        flexibleSearchQuery.setResultClassList(List.of(Integer.class));
        return getFlexibleSearchService().searchUnique(flexibleSearchQuery);
    }


    public PaginatedFlexibleSearchService getPaginatedFlexibleSearchService() {
        return paginatedFlexibleSearchService;
    }

    public void setPaginatedFlexibleSearchService(PaginatedFlexibleSearchService paginatedFlexibleSearchService) {
        this.paginatedFlexibleSearchService = paginatedFlexibleSearchService;
    }
}
