package com.axelor.apps.account.web;

import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.CashInventory;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.db.repo.CashInventoryRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherRepository;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.CashInventoryService;
import com.axelor.apps.base.service.ConvertNumberToFrenchWordsService;
import com.axelor.exception.AxelorException;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.common.base.Strings;
import com.google.inject.Inject;

import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CashInventoryController {

  private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  @Inject
  private final ConvertNumberToFrenchWordsService convertService;

  @Inject
  public CashInventoryController(ConvertNumberToFrenchWordsService convertService) {
    this.convertService = convertService;
  }

  /**
   * Prints the cash inventory report.
   *
   * @param request  The action request containing the context.
   * @param response The action response to set the view with the report link.
   * @throws AxelorException If an error occurs during report generation.
   */
  public void printCashInventory(ActionRequest request, ActionResponse response)
      throws AxelorException {

    CashInventory cashInventory = request.getContext().asType(CashInventory.class);

    String name = I18n.get("Cash");
    if (!Strings.isNullOrEmpty(cashInventory.getRef())) {
      name += " " + cashInventory.getRef();
    }

    String fileLink = ReportFactory.createReport(
        String.format(IReport.CASH_INVENTORY, cashInventory.getOperationTypeSelect()),
        name + "-${date}")
        .addParam("cashInventoryId", cashInventory.getId())
        .generate()
        .getFileLink();

    logger.debug("Printing " + name);

    response.setView(ActionView.define(name).add("html", fileLink).map());
  }

  /**
   * Computes the theoretical solde in words for the cash inventory.
   *
   * @param request  The action request containing the context.
   * @param response The action response to set the theoretical solde in words.
   */
  public void convertTheoricalSoldeInWords(ActionRequest request, ActionResponse response) {
    CashInventory cashInventory = request.getContext().asType(CashInventory.class);

    String[] arrOfStr = cashInventory.getPhysicalSolde().toString().split("\\.");

    String left = convertService.convert(Long.parseLong(arrOfStr[0]));
    String right = convertService.convert(Long.parseLong(arrOfStr[1]));
    String number = left + " dinars algériens et " + right + " Cts";

    response.setValue("theoricalSoldeInWords", number);
  }

  /**
   * Initializes the theoretical solde in words for the cash inventory.
   *
   * @param request  The action request containing the context.
   * @param response The action response to set the theoretical solde value.
   */
  public void initThetoricalSolde(ActionRequest request, ActionResponse response) {
    BigDecimal theoricalSolde = Beans.get(CashInventoryService.class).initThetoricalSolde();
    response.setValue("theoricalSolde", theoricalSolde);
  }

  /**
   * Computes the totals for the cash inventory.
   *
   * @param request  The action request containing the context.
   * @param response The action response to set the computed values.
   */
  public void computeToTals(ActionRequest request, ActionResponse response) {

    CashInventory cashInventory = request.getContext().asType(CashInventory.class);
    if(cashInventory.getCashInventoryLines() != null && cashInventory.getCashInventoryLines().size() != 0){
      Map<String, BigDecimal> map = Beans.get(CashInventoryService.class).computeToTals(cashInventory);
      response.setValues(map);
    }
  }

  /**
   * Retrieves the last cash data and calculates the theoretical solde.
   *
   * @param request  The action request containing the context.
   * @param response The action response to set the theoretical solde value.
   */
  public void getLastCashData(ActionRequest request, ActionResponse response) {
    CashInventory lastCashInventory = Beans.get(CashInventoryRepository.class).all().order("-id").fetchOne();

    List<PaymentVoucher> cashVouchers = Beans.get(PaymentVoucherRepository.class)
        .all()
        .filter("self.operationTypeSelect = 9 and self.cashStatusSelect = 3")
        .fetch();

    BigDecimal totalSolde = lastCashInventory.getPhysicalSolde();

    for (PaymentVoucher paymentVoucher : cashVouchers) {
      switch (paymentVoucher.getDebitCreditSelect()) {
        case "1":
          totalSolde = totalSolde.subtract(paymentVoucher.getPaidAmount());
          break;
        case "2":
          totalSolde = totalSolde.add(paymentVoucher.getPaidAmount());
          break;

        default:
          break;
      }
    }

    response.setValue("theoricalSolde", totalSolde);
  }

  // generate sequence for cash inventory
  public void generateSequence(ActionRequest request, ActionResponse response) throws AxelorException {
    CashInventory cashInventory = request.getContext().asType(CashInventory.class);
    if (cashInventory.getRef() == null || cashInventory.getRef().isEmpty()) {
      String sequence = Beans.get(CashInventoryService.class).getCashInventorySequence(cashInventory);
      response.setValue("ref", sequence);
    }
  }


  public void approveCashInventory(ActionRequest request, ActionResponse response) throws AxelorException{
        CashInventory cashInventoryContext = request.getContext().asType(CashInventory.class);
        CashInventory cashInventory = Beans.get(CashInventoryRepository.class).find(cashInventoryContext.getId());
        Beans.get(CashInventoryService.class).approveCashInventory(cashInventory);
        response.setReload(true);
  }
}
