package com.axelor.apps.hr.web;

import com.axelor.apps.hr.db.Absence;
import com.axelor.apps.hr.db.DailyReport;
import com.axelor.apps.hr.db.Employee;
import com.axelor.apps.hr.db.repo.AbsenceRepository;
import com.axelor.apps.hr.db.repo.DailyReportRepository;
import com.axelor.apps.hr.service.AbsenceServiceImpl;
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 java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

public class AbsenceController {

  public void attachTheAbsenceWithDailyReport(ActionRequest request, ActionResponse response) {
    try {
      Long absenceId = (Long) request.getContext().asType(Absence.class).getId();
      Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);

      LocalDate absenceStartDate = absence.getStartDate().toLocalDate();
      LocalDate absenceEndDate = absence.getEndDate().toLocalDate();
      Employee employee = absence.getEmployee();

      // Fetch all existing daily reports associated with this absence
      List<DailyReport> existingReports =
          Beans.get(DailyReportRepository.class)
              .all()
              .filter("self.absenceSet = :absence")
              .bind("absence", absence)
              .fetch();

      if (existingReports != null && !existingReports.isEmpty()) {
        // Detach absence only from reports that are outside the new date range
        List<DailyReport> reportsToDetach =
            existingReports
                .stream()
                .filter(
                    report ->
                        report.getReportDate().isBefore(absenceStartDate)
                            || report.getReportDate().isAfter(absenceEndDate))
                .collect(Collectors.toList());

        // Detach absence from these specific reports
        if (!reportsToDetach.isEmpty()) {
          Beans.get(AbsenceServiceImpl.class)
              .deAttachTheAbsenceWithDailyReport(absence, reportsToDetach, false);
        }
      }

      List<DailyReport> newReports =
          Beans.get(DailyReportRepository.class)
              .all()
              .filter(
                  "self.employee = :employee and self.reportDate between :absenceStartDate and :absenceEndDate")
              .bind("employee", employee)
              .bind("absenceStartDate", absenceStartDate)
              .bind("absenceEndDate", absenceEndDate)
              .fetch();

      // Check if there are any reports
      if (newReports.isEmpty()) {
        return;
      }

      Beans.get(AbsenceServiceImpl.class).attachTheAbsenceWithDailyReport(absence, newReports);
      response.setReload(true);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void chooseAbsenceType(ActionRequest request, ActionResponse response) {
    try {
      // Get the selected absence type from the request parameters
      Integer selectedType = (Integer) request.getContext().get("selectedType");

      // Get the list of selected absence IDs
      List<Long> absenceIds = (List<Long>) request.getContext().get("_ids");

      // Iterate over the selected absence IDs
      for (Long absenceId : absenceIds) {
        // Find the absence entity by ID
        Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);

        if (absence != null) {
          // Call the chooseAbsenceType method of the service with both absence and selectedType
          Beans.get(AbsenceServiceImpl.class).chooseAbsenceType(absence, selectedType);
        } else {
          // Log a warning or handle the absence being null appropriately
          System.err.println("Absence entity with ID " + absenceId + " not found.");
        }
      }

      // Set reload to true to refresh the view
      response.setReload(true);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void archiveAbsence(ActionRequest request, ActionResponse response) {
    try {
      Long absenceId = (Long) request.getContext().asType(Absence.class).getId();
      Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);

      List<DailyReport> dailyreports =
          Beans.get(DailyReportRepository.class)
              .all()
              .filter("self.absence = :absence")
              .bind("absence", absenceId)
              .fetch();

      Beans.get(AbsenceServiceImpl.class)
          .deAttachTheAbsenceWithDailyReport(absence, dailyreports, true);
      ActionViewBuilder actionView =
          ActionView.define(I18n.get("Absences"))
              .model(Absence.class.getName())
              .add("grid", "absence-grid")
              .add("form", "absence-form");

      response.setView(actionView.map());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void calculateTotalAbsenceHours(ActionRequest request, ActionResponse response) {
    try {
      Absence absence = request.getContext().asType(Absence.class);
      // Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);

      LocalDateTime absenceStartDate = absence.getStartDate();
      LocalDateTime absenceEndDate = absence.getEndDate();
      if (absenceStartDate.isAfter(absenceEndDate)) {
        response.setAlert("Start date cannot be after end date.");
      } else {
        BigDecimal totalAbsenceHours =
            Beans.get(AbsenceServiceImpl.class)
                .calculateTotalAbsenceHours(absenceStartDate, absenceEndDate);
        response.setValue("totalAbsenceHours", totalAbsenceHours);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
