package com.axelor.apps.hr.web;

import com.axelor.apps.hr.db.DailyReport;
import com.axelor.apps.hr.db.Employee;
import com.axelor.apps.hr.db.repo.DailyReportRepository;
import com.axelor.apps.hr.db.repo.EmployeeRepository;
import com.axelor.apps.hr.service.DailyReportService;
import com.axelor.apps.hr.service.DailyReportServiceImpl;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DailyReportController {

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

  /**
   * @param request
   * @param response
   */
  public void workingHours(ActionRequest request, ActionResponse response) {
    try {
      Long dailyReportId = (Long) request.getContext().asType(DailyReport.class).getId();
      DailyReport DailyReport = Beans.get(DailyReportRepository.class).find(dailyReportId);
      if (DailyReport == null) {
        throw new IllegalArgumentException("DailyReport with ID " + dailyReportId + " not found.");
      }
      Beans.get(DailyReportServiceImpl.class).determineShift(DailyReport);
      Beans.get(DailyReportServiceImpl.class).workingHours(DailyReport);
      response.setReload(true);
    } catch (Exception e) {
      System.out.println("\n\n\n\n\n\n\n\n");
      e.printStackTrace();
    }
  }

  public void workingHours1(ActionRequest request, ActionResponse response) {
    try {
      Long dailyReportId = (Long) request.getContext().asType(DailyReport.class).getId();
      DailyReport DailyReport = Beans.get(DailyReportRepository.class).find(dailyReportId);
      if (DailyReport == null) {
        throw new IllegalArgumentException("DailyReport with ID " + dailyReportId + " not found.");
      }
      Beans.get(DailyReportServiceImpl.class).workingHours(DailyReport);
      response.setReload(true);
    } catch (Exception e) {
      System.out.println("\n\n\n\n\n\n\n\n");
      e.printStackTrace();
    }
  }

  public void workingHoursForAll(ActionRequest request, ActionResponse response) {
    try {
      List<DailyReport> dailyReportList =
          Beans.get(DailyReportRepository.class)
              .all()
              .filter("self.isCalculated = ?", false)
              .fetch();

      if (!dailyReportList.isEmpty()) {
        Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
        response.setFlash("Working hours calculated successfully.");
      } else {
        response.setFlash("No new records to process.");
      }

      response.setReload(true);
    } catch (Exception e) {
      log.error("An error occurred while calculating working hours.", e);
      response.setError("An error occurred while calculating working hours.");
    }
  }

  public void workingHoursForSelectedInstances(ActionRequest request, ActionResponse response) {
    List<Long> dailyReportIds = (List<Long>) request.getContext().get("_ids");
    if (dailyReportIds != null && !dailyReportIds.isEmpty()) {

      List<DailyReport> dailyReportList =
          Beans.get(DailyReportRepository.class)
              .all()
              .filter("self.id in ?1 ", dailyReportIds)
              .fetch();

      for (DailyReport dailyReport : dailyReportList) {
        Beans.get(DailyReportServiceImpl.class).determineShift(dailyReport);
      }
      Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
      response.setFlash("Working hours calculated successfully.");
    } else {
      response.setFlash("No Daily report selected");
    }
  }

  public void workingHoursForChangedInstances(ActionRequest request, ActionResponse response) {
    List<DailyReport> dailyReportList =
        Beans.get(DailyReportRepository.class)
            .all()
            .filter("self.isCalculated = ? and self.isChanged = ?", false, true)
            .fetch();

    for (DailyReport dailyReport : dailyReportList) {
      Beans.get(DailyReportServiceImpl.class).determineShift(dailyReport);
    }

    Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
    response.setReload(true);
    response.setFlash("Working hours calculated successfully.");
  }

  public void massDeducePrime(ActionRequest request, ActionResponse response) {

    Integer primeSelection = (Integer) request.getContext().get("primesSelect");
    String startDateStr = (String) request.getContext().get("startDate");
    String endDateStr = (String) request.getContext().get("endDate");

    LocalDate startDate = null;
    LocalDate endDate = null;

    try {
      if (startDateStr != null) {
        startDate = LocalDate.parse(startDateStr);
      }
      if (endDateStr != null) {
        endDate = LocalDate.parse(endDateStr);
      }

      // Validate the dates
      if (startDate == null || endDate == null) {
        response.setFlash("Start date or end date is missing or invalid.");
        return;
      }

      if (startDate.isAfter(endDate)) {
        response.setFlash("Start date cannot be after end date.");
        return;
      }

    } catch (DateTimeParseException e) {
      response.setFlash(
          "Invalid date format for startDate or endDate. Expected format: yyyy-MM-dd.");
      return;
    }

    Object valueToDeduceObj = request.getContext().get("valueToDeduce");

    BigDecimal valueToDeduce = null;
    if (valueToDeduceObj instanceof Integer) {
      valueToDeduce = BigDecimal.valueOf((Integer) valueToDeduceObj);
    } else if (valueToDeduceObj instanceof BigDecimal) {
      valueToDeduce = (BigDecimal) valueToDeduceObj;
    } else if (valueToDeduceObj instanceof String) {
      try {
        valueToDeduce = new BigDecimal((String) valueToDeduceObj);
      } catch (NumberFormatException e) {
        response.setFlash("Value to deduce must be a valid number.");
        return;
      }
    } else {
      response.setFlash(
          "Invalid value to deduce: unsupported type "
              + (valueToDeduceObj != null ? valueToDeduceObj.getClass().getName() : "null"));
      return;
    }

    Object employeesObject = request.getContext().get("employees");

    // Initialize the employees list
    List<Employee> employees = new ArrayList<>();

    if (employeesObject instanceof List) {
      List<LinkedHashMap<String, Object>> employeesList =
          (List<LinkedHashMap<String, Object>>) employeesObject;

      for (LinkedHashMap<String, Object> employeeMap : employeesList) {
        Integer employeeIdInt = (Integer) employeeMap.get("id");

        if (employeeIdInt != null) {
          Long employeeId = employeeIdInt.longValue();
          Employee employee = Beans.get(EmployeeRepository.class).find(employeeId);

          if (employee != null) {
            employees.add(employee);
          }
        }
      }
    }

    if (employees.isEmpty()) {
      response.setFlash("No employees selected.");
      return;
    }

    List<Integer> employeeIds = new ArrayList<>();
    for (Employee employee : employees) {
      employeeIds.add(employee.getId().intValue());
    }

    // Fetch all rapport journaliers within the date range for all employees
    List<DailyReport> dailyReportList =
        Beans.get(DailyReportRepository.class)
            .all()
            .filter(
                "self.employee.id in :employeeIds and self.reportDate >= :startDate and self.reportDate <= :endDate")
            .bind("startDate", startDate)
            .bind("endDate", endDate)
            .bind("employeeIds", employeeIds)
            .fetch();

    try {
      if (!dailyReportList.isEmpty()) {
        Beans.get(DailyReportService.class)
            .massDeducePrimes(dailyReportList, primeSelection, valueToDeduce);
        response.setReload(true);
        response.setFlash("Prime deductions processed successfully.");
      } else {
        response.setFlash("No reports found for the selected date range.");
      }
    } catch (Exception e) {
      TraceBackService.trace(response, e);
      response.setFlash("An error occurred while processing the request.");
    }
  }
}
