package com.axelor.apps.hr.job;

import com.axelor.apps.base.web.AppBaseController;
import com.axelor.apps.hr.service.AuthorizationService;
import com.axelor.apps.hr.service.extra.hours.ExtraHoursService;
import com.axelor.apps.hr.service.leave.LeaveService;
import com.axelor.apps.hr.web.AuthorizationController;
import com.axelor.apps.hr.web.extra.hours.ExtraHoursController;
import com.axelor.apps.hr.web.leave.LeaveController;
import com.axelor.inject.Beans;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wslite.json.JSONArray;
import wslite.json.JSONException;
import wslite.json.JSONObject;
import org.quartz.SchedulerException;

/** An example {@link Job} class that prints a some messages to the stderr. */
public class FetchHrTicketsJob implements Job {

  private final Logger log = LoggerFactory.getLogger(FetchHrTicketsJob.class);

  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException{

    if (isRunning(context)) {
      return;
    }
    
    log.info("Starting the job to fetch HR tickets...");

    String accessToken = null;
    try {
      accessToken = AppBaseController.getAccessToken();
    } catch (Exception e) {
      log.error("Failed to get access token", e);
      return; // Exit the method since the access token is critical to proceed
    }

    if (accessToken == null) {
      log.error("Access token is null, unable to proceed.");
      return;
    }

    final String token = accessToken;

    // Create a thread pool with a fixed number of threads (can adjust based on system resources)
    ExecutorService executorService = Executors.newFixedThreadPool(5);

    try {
      // Extra hours fetch task
      executorService.submit(
          () -> {
            try {
              log.info("Fetching extra hours data...");
              String jsonResponse = Beans.get(ExtraHoursController.class).fetchHS(token);
              log.info("Fetched extra hours data successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(ExtraHoursService.class).saveExtraHours(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchHS.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch extra hours data: ", e);
            }
          });

      // Authorization AA fetch task
      executorService.submit(
          () -> {
            try {
              log.info("Fetching authorization AA...");
              String jsonResponse = Beans.get(AuthorizationController.class).fetchAA(token);
              log.info("Fetched authorization AA successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(AuthorizationService.class).saveAA(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchAA.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch authorization AA: ", e);
            }
          });

      
      // Authorization AE fetch task
      executorService.submit(
          () -> {
            try {
              log.info("Fetching authorization AE...");
              String jsonResponse = Beans.get(AuthorizationController.class).fetchAE(token);
              log.info("Fetched authorization AE successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(AuthorizationService.class).saveAE(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchAE.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch authorization AE: ", e);
            }
          });

      // Authorization BS fetch task
      executorService.submit(
          () -> {
            try {
              log.info("Fetching authorization BS...");
              String jsonResponse = Beans.get(AuthorizationController.class).fetchBS(token);
              log.info("Fetched authorization BS successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(AuthorizationService.class).saveBS(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchBS.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch authorization BS: ", e);
            }
          });

      executorService.submit(
          () -> {
            try {
              log.info("Fetching authorization AP...");
              String jsonResponse = Beans.get(AuthorizationController.class).fetchAP(token);
              log.info("Fetched authorization AP successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(AuthorizationService.class).saveAP(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchAP.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch Salary authorization: ", e);
            }
          });

      // Leave requests fetch task
      executorService.submit(
          () -> {
            try {
              log.info("Fetching leave requests...");
              String jsonResponse = Beans.get(LeaveController.class).fetchCR(token);
              log.info("Fetched leave requests successfully.");
              if (jsonResponse != null) {
                try {
                  JSONArray jsonArray = new JSONArray(jsonResponse);
                  for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Beans.get(LeaveService.class).saveCR(jsonObject);
                  }
                } catch (JSONException e) {
                  log.error("Failed to parse JSON: " + jsonResponse, e);
                }
              } else {
                log.warn("No response received from fetchCR.");
              }
            } catch (Exception e) {
              log.error("Failed to fetch leave requests: ", e);
            }
          });
        

    } finally {
      // Shutdown the ExecutorService gracefully
      executorService.shutdown();
      try {
        if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
          executorService.shutdownNow();
        }
      } catch (InterruptedException e) {
        executorService.shutdownNow();
      }
    }

    log.info("Finished fetching HR tickets.");
  }

  private boolean isRunning(JobExecutionContext context) {
    try {
      return context
          .getScheduler()
          .getCurrentlyExecutingJobs()
          .stream()
          .anyMatch(
              j ->
                  j.getTrigger().equals(context.getTrigger())
                      && !j.getFireInstanceId().equals(context.getFireInstanceId()));
    } catch (SchedulerException e) {
      return false;
    }
  }

}
