package com.axelor.apps.stock.web;

import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.Unit;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.base.service.UnitConversionService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.stock.db.StockLocation;
import com.axelor.apps.stock.db.StockMove;
import com.axelor.apps.stock.db.StockMoveLine;
import com.axelor.apps.stock.db.StockProductionRequest;
import com.axelor.apps.stock.db.StockProductionRequestLine;
import com.axelor.apps.stock.db.repo.StockLocationRepository;
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
import com.axelor.apps.stock.db.repo.StockMoveRepository;
import com.axelor.apps.stock.db.repo.StockProductionRequestLineRepository;
import com.axelor.apps.stock.db.repo.StockProductionRequestRepository;
import com.axelor.apps.stock.service.StockMoveLineService;
import com.axelor.apps.stock.service.StockMoveService;
import com.axelor.apps.stock.service.StockMoveToolService;
import com.axelor.apps.stock.service.StockMoveToolServiceImpl;
import com.axelor.apps.stock.service.config.StockConfigService;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StockProductionRequestService {

  protected StockProductionRequestRepository productionRequestRepository;
  protected StockMoveService stockMoveService;
  protected StockMoveLineService stockMoveLineService;
  protected StockConfigService stockConfigService;
  protected UnitConversionService unitConversionService;
  protected StockMoveLineRepository stockMoveLineRepository;
  protected AppBaseService appBaseService;
  protected StockMoveToolService stockMoveToolService;

  private static final Logger logger =
      LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  @Inject
  public StockProductionRequestService(
      StockProductionRequestRepository productionRequestRepository,
      StockMoveService stockMoveService,
      StockMoveLineService stockMoveLineService,
      StockConfigService stockConfigService,
      UnitConversionService unitConversionService,
      StockMoveLineRepository stockMoveLineRepository,
      StockMoveToolService stockMoveToolService,
      AppBaseService appBaseService) {
    this.productionRequestRepository = productionRequestRepository;
    this.stockMoveService = stockMoveService;
    this.stockMoveLineService = stockMoveLineService;
    this.stockConfigService = stockConfigService;
    this.unitConversionService = unitConversionService;
    this.stockMoveLineRepository = stockMoveLineRepository;
    this.appBaseService = appBaseService;
    this.stockMoveToolService = stockMoveToolService;
  }

  @Transactional(rollbackOn = {Exception.class})
  public void draft(StockProductionRequest stockProductionRequest) {
    stockProductionRequest.setStatusSelect(1);
    productionRequestRepository.save(stockProductionRequest);
  }

  @Transactional(rollbackOn = {Exception.class})
  public void plan(StockProductionRequest stockProductionRequest) throws AxelorException {
    stockProductionRequest.setStatusSelect(2);
    stockProductionRequest.setStockProductionRequestSeq(
        Beans.get(StockMoveToolServiceImpl.class)
            .getSequenceStockProductionRequest(stockProductionRequest));
    productionRequestRepository.save(stockProductionRequest);
  }

  @Transactional(rollbackOn = {Exception.class})
  public void realize(StockProductionRequest stockProductionRequest) {
    stockProductionRequest.setStatusSelect(3);
    productionRequestRepository.save(stockProductionRequest);
  }

  @Transactional(rollbackOn = {Exception.class})
  public void cancel(StockProductionRequest stockProductionRequest) {
    stockProductionRequest.setStatusSelect(4);
    productionRequestRepository.save(stockProductionRequest);
  }

  @Transactional(rollbackOn = {Exception.class})
  public List<Long> createStocksMovesFromStockProductionRequest(
      StockProductionRequest stockProductionRequest) throws AxelorException {

    List<Long> stockMoveList = new ArrayList<>();

    // StockLocationLine stockLocationLine = this.getOrCreateStockLocationLine(stockLocation,
    // product);

    // UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
    // Unit stockLocationLineUnit = stockLocationLine.getUnit();

    // if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
    // qty =
    // unitConversionService.convert(
    //     stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
    // }

    Company company = stockProductionRequest.getCompany();
    StockMove stockMove = this.createStockMove(stockProductionRequest, company, LocalDate.now());

    stockMove.setExTaxTotal(stockMoveToolService.compute(stockMove));

    stockMoveService.plan(stockMove);

    logger.debug("stockMove ************ {}", stockMove.toString());

    stockMoveList.add(stockMove.getId());

    for (StockProductionRequestLine productionRequestLine :
        stockProductionRequest.getStockProductionRequestLineList()) {
      if (productionRequestLine.getIsWithBackorder()) {
        StockMoveLine line =
            this.createStockMoveLine(
                stockMove, productionRequestLine, productionRequestLine.getRealQty());
        logger.debug("createStockMoveLine ************ {}", line.toString());
      }
    }

    logger.debug("stockMoveList ************ {}", stockMoveList);
    return stockMoveList;
  }

  public StockMove createStockMove(
      StockProductionRequest stockProductionRequest,
      Company company,
      LocalDate estimatedDeliveryDate)
      throws AxelorException {

    StockLocation fromStockLocation =
        stockConfigService.getRawMaterialsDefaultStockLocation(
            stockConfigService.getStockConfig(company));
    StockLocationRepository stockLocationRepository = Beans.get(StockLocationRepository.class);

    switch (stockProductionRequest.getFamilleProduit().getId().intValue()) {
        // matiere premiere
      case 67:
        fromStockLocation = stockLocationRepository.find(75L);
        break;
        // MATIERE PREMIERE INJECTABLE
      case 68:
        fromStockLocation = stockLocationRepository.find(75L);
        break;
        // ARTICLES DE CONDITIONEMENT
      case 59:
        fromStockLocation = stockLocationRepository.find(75L);
        break;

      default:
        fromStockLocation =
            stockConfigService.getRawMaterialsDefaultStockLocation(
                stockConfigService.getStockConfig(company));
        break;
    }

    //  stockProductionRequest.getStocklocation();

    StockLocation toStockLocation = stockProductionRequest.getStocklocation();
    // stockConfigService.getCustomerVirtualStockLocation(
    //     stockConfigService.getStockConfig(company));
    int stockType = StockMoveRepository.TYPE_INTERNAL;
    if (stockProductionRequest.getTypeSelect()
        == StockProductionRequestRepository.TYPE_SELECT_RETURN) {
      toStockLocation = fromStockLocation;
      fromStockLocation =
          // stockProductionRequest.getStocklocation();
          stockConfigService.getCustomerVirtualStockLocation(
              stockConfigService.getStockConfig(company));
      stockType = StockMoveRepository.TYPE_INCOMING;
      System.out.println("***************************************yes*********************");
      System.out.println(stockProductionRequest.getTypeSelect());
      System.out.println(StockProductionRequestRepository.TYPE_SELECT_RETURN);
      System.out.println(fromStockLocation);
      System.out.println(toStockLocation);
      System.out.println("***************************************yes*********************");
    }

    StockMove stockMove =
        stockMoveService.createStockMove(
            null,
            null,
            company,
            stockProductionRequest.getPartner(),
            fromStockLocation,
            toStockLocation,
            null,
            estimatedDeliveryDate,
            stockProductionRequest.getNote(),
            null,
            null,
            null,
            null,
            null,
            stockType);

    stockMove.setToAddressStr(null);
    stockMove.setOriginId(stockProductionRequest.getId());
    stockMove.setOriginTypeSelect(StockMoveRepository.ORIGIN_STOCK_PRODUCTION_REQUEST);
    stockMove.setOrigin(stockProductionRequest.getStockProductionRequestSeq());
    stockMove.setStockMoveLineList(new ArrayList<>());
    stockMove.setTradingName(null);
    stockMove.setNote(stockProductionRequest.getNote());
    return stockMove;
  }

  public StockMoveLine createStockMoveLine(
      StockMove stockMove, StockProductionRequestLine productionRequestLine, BigDecimal qty)
      throws AxelorException {

    int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForSalePrice();
    if (this.isStockMoveProduct(productionRequestLine)) {

      Unit unit = productionRequestLine.getProduct().getUnit();

      if (unit != null && !unit.equals(productionRequestLine.getUnit())) {
        qty =
            unitConversionService.convert(
                productionRequestLine.getUnit(),
                unit,
                qty,
                qty.scale(),
                productionRequestLine.getProduct());
      }

      BigDecimal priceDiscounted = productionRequestLine.getUnitPriceTaxed();
      BigDecimal companyUnitPriceUntaxed = productionRequestLine.getCompanyUnitPriceUntaxed();
      BigDecimal unitPriceUntaxed = productionRequestLine.getUnitPriceUntaxed();

      StockMoveLine stockMoveLine =
          stockMoveLineService.createStockMoveLine(
              productionRequestLine.getProduct(),
              productionRequestLine.getProductName(),
              productionRequestLine.getDescription(),
              qty,
              unitPriceUntaxed,
              companyUnitPriceUntaxed,
              companyUnitPriceUntaxed,
              unit,
              stockMove,
              productionRequestLine.getTrackingNumber());
      return stockMoveLine;
    }
    if (productionRequestLine.getDeliveryState() == 0) {
      productionRequestLine.setDeliveryState(
          StockProductionRequestLineRepository.DELIVERY_STATE_NOT_DELIVERED);
    }
    return null;
  }

  @Transactional(rollbackOn = {Exception.class})
  public StockProductionRequest generateReversion(StockProductionRequest stockProductionRequest)
      throws AxelorException {
    StockProductionRequestRepository moveRepository =
        Beans.get(StockProductionRequestRepository.class);
    StockProductionRequestLineRepository moveRepositoryLineRepository =
        Beans.get(StockProductionRequestLineRepository.class);
    StockProductionRequest newStockProductionRequest =
        moveRepository.copy(stockProductionRequest, false);
    newStockProductionRequest.setStockProductionRequestSeq(null);
    newStockProductionRequest.setStatusSelect(StockProductionRequestRepository.STATUS_DRAFT);
    newStockProductionRequest.setTypeSelect(StockProductionRequestRepository.TYPE_SELECT_RETURN);

    for (StockProductionRequestLine requestLine :
        stockProductionRequest.getStockProductionRequestLineList()) {
      StockProductionRequestLine sLine = moveRepositoryLineRepository.copy(requestLine, false);
      newStockProductionRequest.addStockProductionRequestLineListItem(sLine);
    }

    return moveRepository.save(newStockProductionRequest);
    // StockMove stockMove = Beans.get(StockMoveRepository.class).all()
    // .filter(
    //     "self.originTypeSelect = ?1 AND self.originId = ?2 AND self.statusSelect = ?3",
    //     StockMoveRepository.ORIGIN_STOCK_PRODUCTION_REQUEST,
    //     stockProductionRequest.getId())
    // .fetchOne();
    // Optional<StockMove> stockMove =
    // Beans.get(StockMoveServiceImpl.class).copyAndSplitStockMoveReverse(stockMove, false);
    // return stockMove;

  }

  public boolean isStockMoveProduct(StockProductionRequestLine productionRequestLine)
      throws AxelorException {
    return isStockMoveProduct(
        productionRequestLine, productionRequestLine.getStockProductionRequest());
  }

  public boolean isStockMoveProduct(
      StockProductionRequestLine productionRequestLine, StockProductionRequest productionRequest)
      throws AxelorException {

    Product product = productionRequestLine.getProduct();
    return (product != null
        && (product.getProductTypeSelect().equals(ProductRepository.PRODUCT_TYPE_STORABLE)));
  }
}
