package com.axelor.apps.hr.service;

import com.axelor.apps.hr.db.Authorization;
import com.axelor.apps.hr.db.DailyReport;
import com.axelor.apps.hr.db.Employee;
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
import com.axelor.apps.hr.db.repo.DailyReportRepository;
import com.axelor.apps.hr.db.repo.EmployeeRepository;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import javax.inject.Inject;
import wslite.json.JSONException;
import wslite.json.JSONObject;

public class AuthorizationServiceImpl implements AuthorizationService {

  protected EmployeeRepository employeeRepo;
  protected AuthorizationRepository authorizationRepository;
  protected DailyReportRepository dailyReportRepo;

  @Inject
  public AuthorizationServiceImpl(
      EmployeeRepository employeeRepo,
      AuthorizationRepository authorizationRepository,
      DailyReportRepository dailyReportRepo) {
    this.employeeRepo = employeeRepo;
    this.authorizationRepository = authorizationRepository;
    this.dailyReportRepo = dailyReportRepo;
  }

  @Transactional(rollbackOn = {Exception.class})
  public void saveAA(JSONObject jsonObject) throws AxelorException {

    try {
      // Extract fields
      int idInt = jsonObject.getInt("id");
      String id = Integer.toString(idInt);
      String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
      String matricule = jsonObject.getString("matricule");
      String date_absence = jsonObject.getString("date_absence");
      String commentaire = jsonObject.getString("commentaire");
      int validation_status = jsonObject.optInt("validation_status", 2);
      String validateByUser = jsonObject.optString("validate_by_user", null);
      String dateValidation =
          jsonObject.optString("validation_date", null); // Safely get validation_date

      // GET EMPLOYEES
      Employee employee =
          employeeRepo
              .all()
              .filter("self.registrationNumber = :matricule")
              .bind("matricule", matricule)
              .fetchOne();

      if (employee == null) {
        System.err.println("Employee with matricule " + matricule + " not found.");
        return;
      }

      Employee validatedByEmployee = null;

      if (validateByUser != null) {
        validatedByEmployee =
            employeeRepo
                .all()
                .filter("self.registrationNumber = :matricule")
                .bind("matricule", validateByUser)
                .fetchOne();

        if (validatedByEmployee == null) {
          System.err.println("Validator employee with matricule " + validateByUser + " not found.");
          return;
        }
      }

      // Parse validation date (handle null case)
      LocalDate validationDate = null;
      if (dateValidation != null && !dateValidation.isEmpty()) {
        try {
          OffsetDateTime offsetDateTime =
              OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
          validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
        } catch (DateTimeParseException e) {
          System.out.println("Error parsing dateValidation: " + dateValidation);
          validationDate = null;
        }
      }

      // Parse absence Date
      LocalDate absenceDate;
      try {
        absenceDate = LocalDate.parse(date_absence);
      } catch (DateTimeParseException e) {
        System.out.println("Error parsing date_absence: " + date_absence);
        absenceDate = null;
      }

      // Check if Authorization exists by ticketId
      Authorization authorization =
          authorizationRepository
              .all()
              .filter("self.ticketId = :ticketId")
              .bind("ticketId", idInt)
              .fetchOne();

      if (authorization != null) {
        // Authorization exists, compare previous and new status
        int previousStatus = authorization.getStatusSelect(); // Previous status
        int newStatus = validation_status; // New status

        if (previousStatus == 2 && newStatus == 3) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          // Update the fields of the existing Authorization
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);

          // Get Daily report
          DailyReport dailyReport =
              dailyReportRepo
                  .all()
                  .filter("self.employee = :employee and self.reportDate = :reportDate")
                  .bind("employee", employee)
                  .bind("reportDate", absenceDate)
                  .fetchOne();

          if (dailyReport != null) {
            dailyReport.setIsAuthorizedAbsence(true);
          }

        } else if (previousStatus == 2 && newStatus == 4) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);
        }
      } else {
        // Authorization does not exist, create a new one as per the validation_status logic
        authorization = new Authorization();
        authorization.setEmployee(employee);
        authorization.setTicketId(idInt);
        authorization.setTicket(ticketLink);
        authorization.setRequisitionDate(absenceDate);
        authorization.setDescription(commentaire);
        authorization.setStatusSelect(validation_status);
        authorization.setAuthorizationType(2); // Set default authorization type

        if (validation_status == 3) {
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
        } else if (validation_status == 4) {
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
        }

        // Get Daily report
        DailyReport dailyReport =
            dailyReportRepo
                .all()
                .filter("self.employee = :employee and self.reportDate = :reportDate")
                .bind("employee", employee)
                .bind("reportDate", absenceDate)
                .fetchOne();

        if (dailyReport != null) {
          authorization.setDailyReport(dailyReport);
          if (validation_status == 3) dailyReport.setIsAuthorizedAbsence(true);
        }
        // Save the new Authorization
        authorizationRepository.save(authorization);
      }

    } catch (JSONException e) {
      System.err.println("Failed to parse JSON: " + jsonObject.toString());
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Transactional(rollbackOn = {Exception.class})
  public void saveAE(JSONObject jsonObject) throws AxelorException {

    try {
      // Extract fields
      int idInt = jsonObject.getInt("id");
      String id = Integer.toString(idInt);
      String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
      String matricule = jsonObject.getString("matricule");
      String date_absence = jsonObject.getString("date_reprise");
      String commentaire = jsonObject.getString("commentaire");
      int validation_status = jsonObject.optInt("validation_status", 2);
      String validateByUser = jsonObject.optString("validate_by_user", null);
      String dateValidation = jsonObject.optString("validation_date", null);

      // GET EMPLOYEES
      Employee employee =
          employeeRepo
              .all()
              .filter("self.registrationNumber = :matricule")
              .bind("matricule", matricule)
              .fetchOne();

      if (employee == null) {
        System.err.println("Employee with matricule " + matricule + " not found.");
        return;
      }

      Employee validatedByEmployee = null;

      if (validateByUser != null) {
        validatedByEmployee =
            employeeRepo
                .all()
                .filter("self.registrationNumber = :matricule")
                .bind("matricule", validateByUser)
                .fetchOne();

        if (validatedByEmployee == null) {
          System.err.println("Validator employee with matricule " + validateByUser + " not found.");
          return;
        }
      }

      // Parse validation date (handle null case)
      LocalDate validationDate = null;
      if (dateValidation != null && !dateValidation.isEmpty()) {
        try {
          OffsetDateTime offsetDateTime =
              OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
          validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
        } catch (DateTimeParseException e) {
          System.out.println("Error parsing dateValidation: " + dateValidation);
          validationDate = null;
        }
      }

      // Parse Requisition Date
      LocalDate absenceDate;
      try {
        absenceDate = LocalDate.parse(date_absence);
      } catch (DateTimeParseException e) {
        System.out.println("Error parsing date_absence: " + date_absence);
        absenceDate = null;
      }

      // Check if Authorization exists by ticketId
      Authorization authorization =
          authorizationRepository
              .all()
              .filter("self.ticketId = :ticketId")
              .bind("ticketId", idInt)
              .fetchOne();

      if (authorization != null) {
        // Authorization exists, compare previous and new status
        int previousStatus = authorization.getStatusSelect(); // Previous status
        int newStatus = validation_status; // New status

        if (previousStatus == 2 && newStatus == 3) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          // Update the fields of the existing Authorization
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);

          // Get Daily report
          DailyReport dailyReport =
              dailyReportRepo
                  .all()
                  .filter("self.employee = :employee and self.reportDate = :reportDate")
                  .bind("employee", employee)
                  .bind("reportDate", absenceDate)
                  .fetchOne();

          if (dailyReport != null) {
            dailyReport.setIsAuthorizedLateArrival(true);
          }
        } else if (previousStatus == 2 && newStatus == 4) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);
        }
      } else {
        // Authorization does not exist, create a new one as per the validation_status logic
        authorization = new Authorization();
        authorization.setEmployee(employee);
        authorization.setTicketId(idInt);
        authorization.setTicket(ticketLink);
        authorization.setRequisitionDate(absenceDate);
        authorization.setDescription(commentaire);
        authorization.setStatusSelect(validation_status);
        authorization.setAuthorizationType(1); // Set default authorization type

        if (validation_status == 3) {
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
        } else if (validation_status == 4) {
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
        }

        // Get Daily report
        DailyReport dailyReport =
            dailyReportRepo
                .all()
                .filter("self.employee = :employee and self.reportDate = :reportDate")
                .bind("employee", employee)
                .bind("reportDate", absenceDate)
                .fetchOne();

        if (dailyReport != null) {
          authorization.setDailyReport(dailyReport);
          if (validation_status == 3) dailyReport.setIsAuthorizedLateArrival(true);
        }
        // Save the new Authorization
        authorizationRepository.save(authorization);
      }

    } catch (JSONException e) {
      System.err.println("Failed to parse JSON: " + jsonObject.toString());
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Transactional(rollbackOn = {Exception.class})
  public void saveBS(JSONObject jsonObject) throws AxelorException {

    try {
      // Extract fields
      int idInt = jsonObject.getInt("id");
      String id = Integer.toString(idInt);
      String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
      String matricule = jsonObject.getString("matricule");
      String date_absence = jsonObject.getString("date_sortie");
      String commentaire = jsonObject.getString("motif");
      String heure_sortie = jsonObject.getString("heure_sortie");
      int validation_status = jsonObject.optInt("validation_status", 2);
      String validateByUser = jsonObject.optString("validate_by_user", null);
      String dateValidation = jsonObject.optString("validation_date", null);

      // GET EMPLOYEES
      Employee employee =
          employeeRepo
              .all()
              .filter("self.registrationNumber = :matricule")
              .bind("matricule", matricule)
              .fetchOne();

      if (employee == null) {
        System.err.println("Employee with matricule " + matricule + " not found.");
        return;
      }

      Employee validatedByEmployee = null;

      if (validateByUser != null) {
        validatedByEmployee =
            employeeRepo
                .all()
                .filter("self.registrationNumber = :matricule")
                .bind("matricule", validateByUser)
                .fetchOne();

        if (validatedByEmployee == null) {
          System.err.println("Validator employee with matricule " + validateByUser + " not found.");
          return;
        }
      }

      // Parse validation date (handle null case)
      LocalDate validationDate = null;
      if (dateValidation != null && !dateValidation.isEmpty()) {
        try {
          OffsetDateTime offsetDateTime =
              OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
          validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
        } catch (DateTimeParseException e) {
          System.out.println("Error parsing dateValidation: " + dateValidation);
          validationDate = null;
        }
      }

      // Parse Requisition Date
      LocalDate absenceDate;
      try {
        absenceDate = LocalDate.parse(date_absence);
      } catch (DateTimeParseException e) {
        System.out.println("Error parsing date_absence: " + date_absence);
        absenceDate = null;
      }

      // Check if Authorization exists by ticketId
      Authorization authorization =
          authorizationRepository
              .all()
              .filter("self.ticketId = :ticketId")
              .bind("ticketId", idInt)
              .fetchOne();

      if (authorization != null) {
        // Authorization exists, compare previous and new status
        int previousStatus = authorization.getStatusSelect(); // Previous status
        int newStatus = validation_status; // New status

        if (previousStatus == 2 && newStatus == 3) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          // Update the fields of the existing Authorization
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);

          // Get Daily report
          DailyReport dailyReport =
              dailyReportRepo
                  .all()
                  .filter("self.employee = :employee and self.reportDate = :reportDate")
                  .bind("employee", employee)
                  .bind("reportDate", absenceDate)
                  .fetchOne();

          if (dailyReport != null) {
            dailyReport.setIsAuthorizedEarlyDeparture(true);
          }

        } else if (previousStatus == 2 && newStatus == 4) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);
        }
      } else {
        String updatedDescription = commentaire + " - " + heure_sortie;
        // Create an instance of Authorization
        authorization = new Authorization();
        authorization.setEmployee(employee);
        authorization.setTicketId(idInt);
        authorization.setTicket(ticketLink);
        authorization.setRequisitionDate(absenceDate);
        authorization.setDescription(updatedDescription);
        authorization.setStatusSelect(validation_status);
        authorization.setAuthorizationType(0);

        if (validation_status == 3) {
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
        } else if (validation_status == 4) {
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
        }

        // Get Daily report
        DailyReport dailyReport =
            dailyReportRepo
                .all()
                .filter("self.employee = :employee and self.reportDate = :reportDate")
                .bind("employee", employee)
                .bind("reportDate", absenceDate)
                .fetchOne();

        if (dailyReport != null) {
          authorization.setDailyReport(dailyReport);
          if (validation_status == 3) dailyReport.setIsAuthorizedEarlyDeparture(true);
        }
        // Save the new Authorization
        authorizationRepository.save(authorization);
      }
    } catch (JSONException e) {
      System.err.println("Failed to parse JSON: " + jsonObject.toString());
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Transactional(rollbackOn = {Exception.class})
  public void saveAP(JSONObject jsonObject) throws AxelorException {

    try {
      // Extract fields
      int idInt = jsonObject.getInt("id");
      String id = Integer.toString(idInt);
      String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
      String matricule = jsonObject.getString("matricule");
      String date_absence = jsonObject.getString("date_sortie");
      String commentaire = jsonObject.getString("motif");
      String heure_sortie = jsonObject.getString("heure_sortie");
      int validation_status = jsonObject.optInt("validation_status", 2);
      String validateByUser = jsonObject.optString("validate_by_user", null);
      String dateValidation = jsonObject.optString("validation_date", null);

      // GET EMPLOYEES
      Employee employee =
          employeeRepo
              .all()
              .filter("self.registrationNumber = :matricule")
              .bind("matricule", matricule)
              .fetchOne();

      if (employee == null) {
        System.err.println("Employee with matricule " + matricule + " not found.");
        return;
      }

      Employee validatedByEmployee = null;

      if (validateByUser != null) {
        validatedByEmployee =
            employeeRepo
                .all()
                .filter("self.registrationNumber = :matricule")
                .bind("matricule", validateByUser)
                .fetchOne();

        if (validatedByEmployee == null) {
          System.err.println("Validator employee with matricule " + validateByUser + " not found.");
          return;
        }
      }

      // Parse validation date (handle null case)
      LocalDate validationDate = null;
      if (dateValidation != null && !dateValidation.isEmpty()) {
        try {
          OffsetDateTime offsetDateTime =
              OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
          validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
        } catch (DateTimeParseException e) {
          System.out.println("Error parsing dateValidation: " + dateValidation);
          validationDate = null;
        }
      }

      // Parse Requisition Date
      LocalDate absenceDate;
      try {
        absenceDate = LocalDate.parse(date_absence);
      } catch (DateTimeParseException e) {
        System.out.println("Error parsing date_absence: " + date_absence);
        absenceDate = null;
      }

      // Check if Authorization exists by ticketId
      Authorization authorization =
          authorizationRepository
              .all()
              .filter("self.ticketId = :ticketId")
              .bind("ticketId", idInt)
              .fetchOne();

      if (authorization != null) {
        // Authorization exists, compare previous and new status
        int previousStatus = authorization.getStatusSelect(); // Previous status
        int newStatus = validation_status; // New status

        if (previousStatus == 2 && newStatus == 3) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          // Update the fields of the existing Authorization
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);

          // Get Daily report
          DailyReport dailyReport =
              dailyReportRepo
                  .all()
                  .filter("self.employee = :employee and self.reportDate = :reportDate")
                  .bind("employee", employee)
                  .bind("reportDate", absenceDate)
                  .fetchOne();

          if (dailyReport != null) {
            dailyReport.setIsAuthorizedAbsence(true);
          }

        } else if (previousStatus == 2 && newStatus == 4) {
          System.out.println(
              "Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
          authorization.setStatusSelect(newStatus);
          // Save the updated Authorization
          authorizationRepository.save(authorization);
        }
      } else {
        String updatedDescription = commentaire + " - " + heure_sortie;
        // Create an instance of Authorization
        authorization = new Authorization();
        authorization.setEmployee(employee);
        authorization.setTicketId(idInt);
        authorization.setTicket(ticketLink);
        authorization.setRequisitionDate(absenceDate);
        authorization.setDescription(updatedDescription);
        authorization.setStatusSelect(validation_status);
        authorization.setAuthorizationType(0);

        if (validation_status == 3) {
          authorization.setValidatedByEmployee(validatedByEmployee);
          authorization.setValidationDate(validationDate);
        } else if (validation_status == 4) {
          authorization.setRefusedByEmployee(validatedByEmployee);
          authorization.setRefusalDate(validationDate);
        }

        // Get Daily report
        DailyReport dailyReport =
            dailyReportRepo
                .all()
                .filter("self.employee = :employee and self.reportDate = :reportDate")
                .bind("employee", employee)
                .bind("reportDate", absenceDate)
                .fetchOne();

        if (dailyReport != null) {
          authorization.setDailyReport(dailyReport);
          if (validation_status == 3) dailyReport.setIsAuthorizedAbsence(true);
        }
        // Save the new Authorization
        authorizationRepository.save(authorization);
      }
    } catch (JSONException e) {
      System.err.println("Failed to parse JSON: " + jsonObject.toString());
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  // Helper function to parse dates
  private LocalDate parseDate(String dateString) {
    try {
      OffsetDateTime offsetDateTime =
          OffsetDateTime.parse(dateString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
      return offsetDateTime.toLocalDate();
    } catch (DateTimeParseException e) {
      System.out.println("Error parsing date: " + dateString);
      return null;
    }
  }
}
