package com.axelor.apps.supplychain.web;

import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceTemplate;
import com.axelor.apps.account.db.repo.InvoiceTemplateRepository;
import com.axelor.apps.base.db.Wizard;
import com.axelor.apps.purchase.db.ImportationFolder;
import com.axelor.apps.purchase.db.repo.ImportationFolderRepository;
import com.axelor.apps.purchase.service.print.ImportationFolderPrintService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.stock.db.ImportationFolderCostPrice;
import com.axelor.apps.stock.db.StockMoveLine;
import com.axelor.apps.stock.db.repo.ImportationFolderCostPriceRepository;
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
import com.axelor.apps.stock.exception.IExceptionMessage;
import com.axelor.apps.supplychain.service.ImportationFolderServiceImpl;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.db.mapper.Mapper;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.axelor.rpc.Context;
import com.google.common.base.Joiner;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wslite.json.JSONException;

public class ImportationFolderController {

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

  public void calculateAvgPrice(ActionRequest request, ActionResponse response)
      throws MalformedURLException, JSONException, AxelorException {

    ImportationFolder iimportationFolder =
        (ImportationFolder) request.getContext().asType(ImportationFolder.class);
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find(iimportationFolder.getId());
    List<StockMoveLine> stockMoveLines = importationFolder.getStockMoveLineList();

    List<Long> invoiceIds =
        Beans.get(ImportationFolderServiceImpl.class)
            .calculateAvgPriceAndGenerateInvoice(stockMoveLines, importationFolder);

    response.setView(
        ActionView.define("Invoice")
            .model(Invoice.class.getName())
            .add("grid", "invoice-grid")
            .add("form", "invoice-form")
            .domain("self.id in (" + Joiner.on(",").join(invoiceIds) + ")")
            .param("forceEdit", "true")
            .context("todayDate", Beans.get(AppSupplychainService.class).getTodayDate())
            .map());
  }

  public void computeCostPrice(ActionRequest request, ActionResponse response)
      throws MalformedURLException, JSONException, AxelorException {

    ImportationFolder iimportationFolder =
        (ImportationFolder) request.getContext().asType(ImportationFolder.class);
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find(iimportationFolder.getId());

    String msg = Beans.get(ImportationFolderServiceImpl.class).computeCostPrice(importationFolder);

    response.setAlert(msg);
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  public void setStockMoveLineCurrenyRate(ActionRequest request, ActionResponse response) {
    try {
      List<HashMap> selectedStockMoveLineMapList =
          (List<HashMap>) request.getContext().get("stockMoveLineList");
      Map importationFolderMap =
          (Map<String, Object>) request.getContext().get("importationFolder");
      if (selectedStockMoveLineMapList == null) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_14));
        return;
      }

      List<StockMoveLine> stockMoveLineList = new ArrayList<>();
      StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
      for (HashMap map : selectedStockMoveLineMapList) {
        StockMoveLine stockMoveLine = (StockMoveLine) Mapper.toBean(StockMoveLine.class, map);
        stockMoveLineList.add(stockMoveLineRepo.find(stockMoveLine.getId()));
      }

      if (stockMoveLineList.isEmpty()) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_15));
        return;
      }

      BigDecimal currencyRate = new BigDecimal(request.getContext().get("currencyRate").toString());
      if (currencyRate == null || currencyRate.compareTo(BigDecimal.ZERO) < 0) {
        response.setFlash("Please enter a valid currency rate");
        return;
      }

      ImportationFolder importationFolder =
          Mapper.toBean(ImportationFolder.class, importationFolderMap);
      importationFolder =
          Beans.get(ImportationFolderRepository.class).find(importationFolder.getId());
      Beans.get(ImportationFolderServiceImpl.class)
          .setStockMoveLineCurrenyRate(stockMoveLineList, currencyRate);
      response.setCanClose(true);
    } catch (Exception e) {
      TraceBackService.trace(response, e);
    }
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  public void setStockMoveLineFreight(ActionRequest request, ActionResponse response) {
    try {
      List<HashMap> selectedStockMoveLineMapList =
          (List<HashMap>) request.getContext().get("stockMoveLineList");
      Map importationFolderMap =
          (Map<String, Object>) request.getContext().get("importationFolder");
      if (selectedStockMoveLineMapList == null) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_14));
        return;
      }

      List<StockMoveLine> stockMoveLineList = new ArrayList<>();
      StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
      for (HashMap map : selectedStockMoveLineMapList) {
        StockMoveLine stockMoveLine = (StockMoveLine) Mapper.toBean(StockMoveLine.class, map);
        stockMoveLineList.add(stockMoveLineRepo.find(stockMoveLine.getId()));
      }

      if (stockMoveLineList.isEmpty()) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_15));
        return;
      }

      BigDecimal freight = new BigDecimal(request.getContext().get("freight").toString());
      if (freight == null || freight.compareTo(BigDecimal.ZERO) < 0) {
        response.setFlash("Please enter a valid freight");
        return;
      }

      ImportationFolder importationFolder =
          Mapper.toBean(ImportationFolder.class, importationFolderMap);
      importationFolder =
          Beans.get(ImportationFolderRepository.class).find(importationFolder.getId());
      Beans.get(ImportationFolderServiceImpl.class)
          .setStockMoveLineFreight(stockMoveLineList, freight);
      response.setCanClose(true);
    } catch (Exception e) {
      TraceBackService.trace(response, e);
    }
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  public void setStockMoveLineNetMass(ActionRequest request, ActionResponse response) {
    try {
      List<HashMap> selectedStockMoveLineMapList =
          (List<HashMap>) request.getContext().get("stockMoveLineList");
      Map importationFolderMap =
          (Map<String, Object>) request.getContext().get("importationFolder");
      if (selectedStockMoveLineMapList == null) {
        response.setFlash("No selected move line");
        return;
      }

      List<StockMoveLine> stockMoveLineList = new ArrayList<>();
      StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
      for (HashMap map : selectedStockMoveLineMapList) {
        StockMoveLine stockMoveLine = (StockMoveLine) Mapper.toBean(StockMoveLine.class, map);
        stockMoveLineList.add(stockMoveLineRepo.find(stockMoveLine.getId()));
      }

      if (stockMoveLineList.isEmpty()) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_15));
        return;
      }

      BigDecimal netMass = new BigDecimal(request.getContext().get("netMass").toString());
      if (netMass == null || netMass.compareTo(BigDecimal.ZERO) < 0) {
        response.setFlash("Please enter a valid mass");
        return;
      }

      ImportationFolder importationFolder =
          Mapper.toBean(ImportationFolder.class, importationFolderMap);
      importationFolder =
          Beans.get(ImportationFolderRepository.class).find(importationFolder.getId());
      Beans.get(ImportationFolderServiceImpl.class)
          .setStockMoveLineNetMass(stockMoveLineList, netMass);
      response.setCanClose(true);
    } catch (Exception e) {
      TraceBackService.trace(response, e);
    }
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  public void setStockMoveLineVolume(ActionRequest request, ActionResponse response) {
    try {
      List<HashMap> selectedStockMoveLineMapList =
          (List<HashMap>) request.getContext().get("stockMoveLineList");
      Map importationFolderMap =
          (Map<String, Object>) request.getContext().get("importationFolder");
      if (selectedStockMoveLineMapList == null) {
        response.setFlash("No selected move line");
        return;
      }

      List<StockMoveLine> stockMoveLineList = new ArrayList<>();
      StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
      for (HashMap map : selectedStockMoveLineMapList) {
        StockMoveLine stockMoveLine = (StockMoveLine) Mapper.toBean(StockMoveLine.class, map);
        stockMoveLineList.add(stockMoveLineRepo.find(stockMoveLine.getId()));
      }

      if (stockMoveLineList.isEmpty()) {
        response.setFlash(I18n.get(IExceptionMessage.STOCK_MOVE_15));
        return;
      }

      BigDecimal volume = new BigDecimal(request.getContext().get("volume").toString());
      if (volume == null || volume.compareTo(BigDecimal.ZERO) < 0) {
        response.setFlash("Please enter a valid mass");
        return;
      }

      ImportationFolder importationFolder =
          Mapper.toBean(ImportationFolder.class, importationFolderMap);
      importationFolder =
          Beans.get(ImportationFolderRepository.class).find(importationFolder.getId());
      Beans.get(ImportationFolderServiceImpl.class)
          .setStockMoveLineVolume(stockMoveLineList, volume);
      response.setCanClose(true);
    } catch (Exception e) {
      TraceBackService.trace(response, e);
    }
  }

  public void validateCostPrice(ActionRequest request, ActionResponse response) {

    ImportationFolderCostPrice importationFolderCostPrice =
        Beans.get(ImportationFolderCostPriceRepository.class)
            .find(request.getContext().asType(ImportationFolderCostPrice.class).getId());
    // sophal refresh purchase order price

    try {
      Beans.get(ImportationFolderServiceImpl.class).validateCostPrice(importationFolderCostPrice);
      response.setReload(true);
    } catch (Exception e) {
      System.out.println(e.toString());
    }
  }

  public void massValidateCostPrice(ActionRequest request, ActionResponse response) {

    ImportationFolder iimportationFolder =
        (ImportationFolder) request.getContext().asType(ImportationFolder.class);
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find(iimportationFolder.getId());

    List<ImportationFolderCostPrice> importationFolderCostPriceList =
        importationFolder.getImportationFolderCostPriceList();
    // TODO gorup by product and stockmove to minimize the proccessed line
    for (ImportationFolderCostPrice line : importationFolderCostPriceList) {
      try {
        Beans.get(ImportationFolderServiceImpl.class).validateCostPrice(line);
      } catch (Exception e) {
        System.out.println(e.toString());
      }
    }
    response.setReload(true);
  }

  public void confirmRejectView(ActionRequest request, ActionResponse response) {
    ImportationFolder ImportationFolderContext =
        request.getContext().asType(ImportationFolder.class);
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find(ImportationFolderContext.getId());

    ActionViewBuilder confirmView =
        ActionView.define("Confirm rejection")
            .model(Wizard.class.getName())
            .add("form", "action-importation-folder-rejection-form")
            .param("popup", "true")
            .param("show-toolbar", "false")
            .param("show-confirm", "false")
            .param("popup-save", "false")
            .param("forceEdit", "true");

    confirmView.context("importationFolderId", importationFolder.getId());
    response.setView(confirmView.map());
  }

  public void rejectImportationFolder(ActionRequest request, ActionResponse response)
      throws AxelorException {

    int importationFolderId = (int) request.getContext().get("importationFolderId");
    String rejectionRaison = (String) request.getContext().get("rejectionRaison");
    String rejectionInstance = (String) request.getContext().get("$rejectedInstanceSelect");
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find((long) importationFolderId);

    Beans.get(ImportationFolderServiceImpl.class)
        .rejectImportationFolder(importationFolder, rejectionRaison);

    response.setCanClose(true);
  }

  public void print(ActionRequest request, ActionResponse response) {

    Context context = request.getContext();
    String fileLink;
    String title;

    ImportationFolderPrintService importationFolderPrintService =
        Beans.get(ImportationFolderPrintService.class);

    try {
      if (context.get("id") != null) {
        ImportationFolder importationFolder = request.getContext().asType(ImportationFolder.class);
        title = importationFolderPrintService.getFileName(importationFolder);
        fileLink =
            importationFolderPrintService.printCostPriceSheet(
                importationFolder, ReportSettings.FORMAT_PDF);
        logger.debug("Printing " + title);
      } else {
        throw new AxelorException(
            TraceBackRepository.CATEGORY_MISSING_FIELD,
            I18n.get(IExceptionMessage.INVENTORY_3_DATA_NULL_OR_EMPTY));
      }
      response.setView(ActionView.define(title).add("html", fileLink).map());
    } catch (Exception e) {
      TraceBackService.trace(response, e);
    }
  }

  public void generateFromModel(ActionRequest request, ActionResponse response)
      throws AxelorException {
    Long importationFolderId = (Long) request.getContext().get("id");
    ImportationFolder importationFolder =
        Beans.get(ImportationFolderRepository.class).find((long) importationFolderId);
    InvoiceTemplate template = (InvoiceTemplate) request.getContext().get("$invoiceTemplate");
    InvoiceTemplate invoiceTemplate =
        Beans.get(InvoiceTemplateRepository.class).find(template.getId());

    Invoice invoice =
        Beans.get(ImportationFolderServiceImpl.class)
            .generateFromModel(importationFolder, invoiceTemplate);

    response.setView(
        ActionView.define("Invoice")
            .model(Invoice.class.getName())
            .add("grid", "invoice-grid")
            .add("form", "invoice-form")
            .param("forceEdit", "true")
            .context("_showRecord", String.valueOf(invoice.getId()))
            .context("_operationTypeSelect", invoice.getOperationTypeSelect())
            .context("todayDate", Beans.get(AppSupplychainService.class).getTodayDate())
            .map());
  }
}
