package com.braintree.delivery.dao.impl;

import com.braintree.delivery.dao.BraintreeCountyZoneDeliveryModeDao;
import de.hybris.platform.commerceservices.delivery.dao.impl.DefaultCountryZoneDeliveryModeDao;
import de.hybris.platform.core.model.ItemModel;
import de.hybris.platform.core.model.c2l.CountryModel;
import de.hybris.platform.core.model.c2l.CurrencyModel;
import de.hybris.platform.core.model.order.AbstractOrderModel;
import de.hybris.platform.core.model.order.delivery.DeliveryModeModel;
import de.hybris.platform.deliveryzone.constants.GeneratedZoneDeliveryModeConstants.Relations;
import de.hybris.platform.deliveryzone.constants.GeneratedZoneDeliveryModeConstants.TC;
import de.hybris.platform.deliveryzone.model.ZoneDeliveryModeModel;
import de.hybris.platform.deliveryzone.model.ZoneDeliveryModeValueModel;
import de.hybris.platform.jalo.link.Link;
import de.hybris.platform.servicelayer.search.SearchResult;
import de.hybris.platform.util.PriceValue;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultBraintreeCountyZoneDeliveryModeDao extends DefaultCountryZoneDeliveryModeDao implements
        BraintreeCountyZoneDeliveryModeDao {

    private static final String ZONE_COUNTRY_RELATION = "ZoneCountryRelation";
    public static final String DELIVERY_COUNTRY = "deliveryCountry";
    public static final String CURRENCY = "currency";
    private static final String NET = "net";
    private static final String ACTIVE = "active";
    private static final String STORE = "store";
    private static final String DELIVERY_MODE = "deliveryMode";
    private static final String CURR = "curr";
    private static final String COUNTRY = "country";
    private static final String AMOUNT = "amount";
    private static final String STORE_TO_DELIVERY_MODE_RELATION = "BaseStore2DeliveryModeRel";

    private static final String FIND_DELIVERY_MODES_QUERY = "SELECT DISTINCT {zdm:" + ItemModel.PK + "} FROM { "
            + ZoneDeliveryModeValueModel._TYPECODE + " AS val JOIN "
            + ZoneDeliveryModeModel._TYPECODE + " AS zdm ON {val:" + ZoneDeliveryModeValueModel.DELIVERYMODE + "}={zdm:"
            + ItemModel.PK + "} JOIN " + ZONE_COUNTRY_RELATION + " AS z2c ON {val:" + ZoneDeliveryModeValueModel.ZONE + "}={z2c:"
            + Link.SOURCE + "} JOIN " + STORE_TO_DELIVERY_MODE_RELATION + " AS s2d ON {val:"
            + ZoneDeliveryModeValueModel.DELIVERYMODE + "}={s2d:" + Link.TARGET + "} } WHERE {val:"
            + ZoneDeliveryModeValueModel.CURRENCY + "}=?" + CURRENCY + " AND {z2c:" + Link.TARGET + "}=?" + DELIVERY_COUNTRY + " AND {s2d:"
            + Link.SOURCE + "}=?" + STORE + " AND {zdm:" + ZoneDeliveryModeModel.NET + "}=?" + NET + " AND {zdm:"
            + ZoneDeliveryModeModel.ACTIVE + "}=?" + ACTIVE;

    private static final String COUNT_PRICE_FOR_DELIVERY_MODE_QUERY = "SELECT {v."
            + ZoneDeliveryModeValueModel.PK + "} " + "FROM {" + TC.ZONEDELIVERYMODEVALUE + " AS v JOIN "
            + Relations.ZONECOUNTRYRELATION + " AS z2cRel ON {v.zone}={z2cRel.source} } WHERE {v."
            + DELIVERY_MODE + "} = ?" + DELIVERY_MODE + " AND {v.currency} = ?" + CURR + " AND {v.minimum"
            + "} <= ?" + AMOUNT + " AND {z2cRel.target} = ?" + COUNTRY + " ORDER BY {v.minimum} DESC ";

    @Override
    public List<DeliveryModeModel> findDeliveryModes(AbstractOrderModel abstractOrder, CountryModel countryModel) {
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put(DELIVERY_COUNTRY, countryModel);
        params.put(CURRENCY, abstractOrder.getCurrency());
        params.put(NET, abstractOrder.getNet());
        params.put(ACTIVE, Boolean.TRUE);
        params.put(STORE, abstractOrder.getStore());

        return doSearch(FIND_DELIVERY_MODES_QUERY, params, DeliveryModeModel.class);
    }

    @Override
    public PriceValue countPriceForDeliveryMode(DeliveryModeModel deliveryModeModel, AbstractOrderModel orderModel,
                                                CountryModel countryModel) {
        CurrencyModel curr = orderModel.getCurrency();
        Map<String, Object> parameters = new HashMap<>();
        parameters.put(DELIVERY_MODE, deliveryModeModel);
        parameters.put(CURR, curr);
        parameters.put(COUNTRY, countryModel);
        parameters.put(AMOUNT, orderModel.getSubtotal());
        SearchResult<ZoneDeliveryModeValueModel> search = search(COUNT_PRICE_FOR_DELIVERY_MODE_QUERY, parameters);
        if (search.getCount() > 0) {
            ZoneDeliveryModeValueModel bestMatch = search.getResult().get(0);
            CurrencyModel myCurr = bestMatch.getCurrency();
            if (curr != null && myCurr != null && curr.getIsocode().equalsIgnoreCase(myCurr.getIsocode())) {
                return new PriceValue(curr.getIsocode(), bestMatch.getValue(), orderModel.getNet());
            }
        }
        return null;
    }

}
