/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2019 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.axelor.apps.base.service;

import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.PartnerPriceList;
import com.axelor.apps.base.db.PriceList;
import com.axelor.apps.base.db.repo.PartnerPriceListRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.exceptions.IExceptionMessage;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.tool.StringTool;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class PartnerPriceListServiceImpl implements PartnerPriceListService {

  protected AppBaseService appBaseService;

  @Inject
  public PartnerPriceListServiceImpl(AppBaseService appBaseService) {
    this.appBaseService = appBaseService;
  }

  @Override
  public void checkDates(PartnerPriceList partnerPriceList) throws AxelorException {
    Set<PriceList> priceListSet = partnerPriceList.getPriceListSet();

    if (priceListSet == null) {
      return;
    }
    Set<PriceList> sortedPriceListSet =
        priceListSet
            .stream()
            .sorted(
                Comparator.comparing(
                    priceList ->
                        priceList.getApplicationBeginDate() != null
                            ? priceList.getApplicationBeginDate()
                            : LocalDate.MIN))
            .collect(Collectors.toSet());
    LocalDate beginDate;
    LocalDate previousEndDate = LocalDate.MIN;
    String previousTitle = "";
    for (PriceList priceList : sortedPriceListSet) {
      beginDate =
          priceList.getApplicationBeginDate() != null
              ? priceList.getApplicationBeginDate()
              : LocalDate.MIN;
      if (beginDate.compareTo(previousEndDate) < 0) {
        throw new AxelorException(
            TraceBackRepository.CATEGORY_INCONSISTENCY,
            String.format(
                I18n.get(IExceptionMessage.PARTNER_PRICE_LIST_DATE_INCONSISTENT),
                previousTitle.replace("%", "%%"),
                priceList.getTitle().replace("%", "%%")),
            partnerPriceList);
      }
      previousEndDate =
          priceList.getApplicationEndDate() != null
              ? priceList.getApplicationEndDate()
              : LocalDate.MAX;
      previousTitle = priceList.getTitle();
    }
  }

  @Override
  public PriceList getDefaultPriceList(Partner partner, int priceListTypeSelect) {
    if (partner == null) {
      return null;
    }
    partner = Beans.get(PartnerRepository.class).find(partner.getId());
    PartnerPriceList partnerPriceList = getPartnerPriceList(partner, priceListTypeSelect);
    if (partnerPriceList == null) {
      return null;
    }
    Set<PriceList> priceListSet = partnerPriceList.getPriceListSet();
    if (priceListSet == null) {
      return null;
    }
    List<PriceList> priceLists =
        priceListSet
            .stream()
            .filter(
                priceList ->
                    (priceList.getApplicationBeginDate() == null
                            || priceList
                                    .getApplicationBeginDate()
                                    .compareTo(appBaseService.getTodayDate())
                                <= 0)
                        && (priceList.getApplicationEndDate() == null
                            || priceList
                                    .getApplicationEndDate()
                                    .compareTo(appBaseService.getTodayDate())
                                >= 0))
            .collect(Collectors.toList());
    if (priceLists.size() == 1) {
      return priceLists.get(0);
    } else {
      return null;
    }
  }

  public String getPriceListDomain(Partner partner, int priceListTypeSelect) {
    if (partner == null) {
      return "self.id IN (0)";
    }
    // get all non exclusive partner price lists
    List<PartnerPriceList> partnerPriceLists =
        Beans.get(PartnerPriceListRepository.class)
            .all()
            .filter("self.typeSelect = :_priceListTypeSelect " + "AND self.isExclusive = false")
            .bind("_priceListTypeSelect", priceListTypeSelect)
            .fetch();
    // get (maybe exclusive) list for the partner
    PartnerPriceList partnerPriceList = getPartnerPriceList(partner, priceListTypeSelect);
    if (partnerPriceList != null && partnerPriceList.getIsExclusive()) {
      partnerPriceLists.add(partnerPriceList);
    }
    if (partnerPriceLists.isEmpty()) {
      return "self.id IN (0)";
    }
    List<PriceList> priceLists =
        partnerPriceLists
            .stream()
            .flatMap(partnerPriceList1 -> partnerPriceList1.getPriceListSet().stream())
            .filter(
                priceList ->
                    priceList.getIsActive()
                        && (priceList.getApplicationBeginDate() == null
                            || priceList
                                    .getApplicationBeginDate()
                                    .compareTo(appBaseService.getTodayDate())
                                <= 0)
                        && (priceList.getApplicationEndDate() == null
                            || priceList
                                    .getApplicationEndDate()
                                    .compareTo(appBaseService.getTodayDate())
                                >= 0))
            .collect(Collectors.toList());
    return "self.id IN (" + StringTool.getIdListString(priceLists) + ")";
  }

  public PartnerPriceList getPartnerPriceList(Partner partner, int priceListTypeSelect) {
    if (priceListTypeSelect == PriceListRepository.TYPE_SALE) {
      return partner.getSalePartnerPriceList();
    } else if (priceListTypeSelect == PriceListRepository.TYPE_PURCHASE) {
      return partner.getPurchasePartnerPriceList();
    }
    return null;
  }
}
