import store from "../../redux/store";
import Database from "../../../../../Components/common/DAsyncStorage";
import { CreateActivityId } from "../OfflineFlow/CreateActivityId";
import { reuploadFailedDocuments } from "../ReUpload/Utils";
import { BackgroundDocumentLast } from "../SilentUpload/BackgroundDocumentLast";
import CONFIGS from "./NotificationsConfig";
import {
  updateNotificationContent,
  createDefaultNotificationConfig,
} from "./BackgroundTasksUtils";
import {
  createPromisifiedTask,
  startBackgroundProcess,
} from "./BackgroundTasks";
import BackgroundService from "react-native-background-actions";
import UploadFile from "../UploadFile";
// import { addSensorImageData } from "./BackgroundSensorData";
import { async } from "validate.js";
import { UELogEvent } from "react-native-digitcamera/src/common/libEventLog/UserExperior/LibUserExperior";
import { updateActivityStatus } from "react-native-digitcamera/src/Screens/OfflineFlow/CommonFunc";
import { dlog } from "react-native-digitcamera/src/common/DLogger";

const CHECK_UPLOAD_STATUS_INTERVAL = 5000;

function dLog() {
  if (__DEV__) {
    console.log("[BACKGROUND] [INFO] . ", ...arguments);
  }
}

function dError() {
  if (__DEV__) {
    console.log("[BACKGROUND] [ERROR] . ", ...arguments);
  }
}

const uploadOnlineDataInBackground = async () => {
  //Let the background video uploading finish first which is started by default
  //then start below task immediately

  const mediaStatusArray = await Database.get("PIMediaStatus");
  const dataToUpload = mediaStatusArray.filter(
    (item) => item?.status === "failed"
  );

  dLog(
    "uploadOnlineDataInBackground . dataToUpload ",
    dataToUpload ?? "undefined"
  );

  if (dataToUpload) {
    try {
      dataToUpload.forEach((item) => {
        let uri = item?.uri;
        let imageName = item?.imageName;
        let ext = imageName == "VDO" ? ".mp4" : ".jpg";
        console.log(
          "[BACKGROUND] - [INFO]  . uploadOnlineDataInBackground . forEach . Item - ",
          item
        );
        UploadFile(
          uri,
          imageName,
          ext,
          () => {
            //   props.navigation.navigate("WithQuote");
          },
          async () => {
            await addSensorImageData(ext, true, imageName);
            addSensorDataCallback(sensorImageDetails);
          },
          async () => {
            addSensorImageData(ext, false, imageName);
            await addSensorDataCallback(sensorImageDetails);
          }
        );
      });
    } catch (error) {
      console.log(
        "[BACKGROUND] [ERROR]. Error in uploadOnlineDataInBackground - Message",
        error?.message
      );
    }
  } else {
    dLog("dataToUpload is Empty");
  }
};

const uploadOfflineDataInBackground = async (a, b, resolve) => {
  try {
    CreateActivityId(a, b, resolve);
  } catch (error) {
    dError(" . in uploadOfflineDataInBackground - Message", error?.message);
  }
};

//helper function
const returnFound = (item1, item2) => {
  if (
    item1.imageName === item2.imageName &&
    item1.activityId === item2.activityId &&
    item2.status === "uploaded"
  ) {
    return true;
  }
  return false;
};

const checkUploadStatus = (backgroundUploadRetryCount, backgroundResolve) => {
  const interval = setInterval(async () => {
    // dLog("checkUploadStatus . PIOnProgress . progressFlag - ", progressFlag);

    // if (!progressFlag) {
    //   clearInterval(interval);
    //   backgroundResolve();
    //   // return;
    // }

    // dLog("checkUploadStatus . PIOnProgress . here - ");

    const mediaStatusArray = await Database.get("PIMediaStatus");

    var PIVechicleData = await Database.get("PIVechicleData");
    dLog(
      "mediaStatusObjs in SilentUploadUtils: ",
      JSON.stringify(mediaStatusArray, null, " "),
      JSON.stringify(PIVechicleData, null, " ")
    );
    var currentActivityData = mediaStatusArray?.filter((activity) => {
      dLog("activity.activityId", JSON.stringify(activity, null, " . "));
      dLog(
        "PIVechicleData?.activityId",
        JSON.stringify(PIVechicleData, null, " . ")
      );
      return activity.activityId == PIVechicleData?.activityId;
    });

    dLog(
      "SilentUploadUtils currentActivityData : ",
      JSON.stringify(currentActivityData, null, "  ")
    );
    var allDocuments = currentActivityData?.[0]?.mediaUpload;
    var totalLength = allDocuments?.length;

    dLog("checkUploadStatus . mediaStatusArray - ", mediaStatusArray);

    const uploadedArr =
      allDocuments.filter((item) => item?.status === "uploaded") ?? [];
    const failureArr =
      allDocuments.filter((item) => item?.status === "failed") ?? [];

    dLog(
      "checkUploadStatus . uploadedArr - ",
      uploadedArr,
      "failureArr",
      failureArr
    );

    const uLength = uploadedArr.length;
    const fLength = failureArr.length;

    dLog(
      "totalLength - ",
      totalLength,
      " uploadedLength - ",
      uLength,
      " failureLength - ",
      fLength
    );

    if (uLength + fLength > totalLength) {
      /**
       * This is to remove extra data present is failed upload
       * that is already uploaded
       * */

      failureArr.forEach((fItem) => {
        allDocuments.forEach((mItem) => {
          if (returnFlag(fItem, mItem)) {
            dlog(
              "found duplicate imagename",
              fItem.imageName,
              "activityId",
              fItem.activityId
            );
            store.dispatch({
              type: "REMOVE_FAILED_DATA",
              payload: {
                imageName: fItem.imageName,
                activityId: fItem.activityId,
              },
            });
          }
        });
      });
    }

    if (uLength + fLength === totalLength) {
      //Clear the interval
      clearInterval(interval);
      if (uLength === totalLength) {
        dLog("everything uploaded calling document last");
        callDocumentLast(currentActivityData?.[0], backgroundResolve);
      }
      if (fLength > 0) {
        if (backgroundUploadRetryCount < 2) {
          UELogEvent("Reuploading documents", {
            "Retry Count": `${backgroundUploadRetryCount}`,
          });
          backgroundUploadRetryCount++;
          dLog(
            "failed upload, retrying for ",
            backgroundUploadRetryCount,
            " times"
          );
          reuploadDocument(failureArr);
          if (interval) {
            clearInterval(interval);
          }
          checkUploadStatus(backgroundUploadRetryCount, backgroundResolve);
        } else {
          if (interval) {
            clearInterval(interval);
          }
          // Update Notification about
          // Failure occured while uploading 3rd time
          dLog(`Failed third time`);

          updateNotificationContent(CONFIGS.BG_KILLED_UPLOAD_FAILURE);

          await Database.set("PIReUploadFailed", "true");
          await updateActivityStatus("FAILED");

          // Show notification that failure happend
          // for 10 sec
          setTimeout(() => {
            backgroundResolve();
          }, 10000);
        }
      }
    }
  }, CHECK_UPLOAD_STATUS_INTERVAL);
};

const callDocumentLast = (activityData, backgroundResolve) => {
  //call document last here
  dLog("Calling document last");
  const { activityId, activityTypeId, regNumber, quoteNumber } = activityData;
  BackgroundDocumentLast(
    {
      activityID: activityId,
      activityTypeId,
      licensePlateNumber: regNumber,
      quoteNumber,
    },
    backgroundResolve
  );
};

const reuploadDocument = async (failureData) => {
  await Database.set("PIReUploadFailed", "false");
  let sensorImageDetails = [];
  dLog("Calling reupload Document");

  reuploadFailedDocuments(failureData, (sensorImageDetails) => {
    store.dispatch({
      type: "SENSOR_DETAILS",
      payload: sensorImageDetails,
    });
  });
};

export const startOfflineBackgroundUpload = async (flag) => {
  let PIMediaStatus = await Database.get("PIMediaStatus");

  let offlineImageData = PIMediaStatus.filter((activity) => {
    return activity.activityStatus == "IN-PROGRESS";
  });

  // TRUE - if user has reached to any progress screen then only we will start the upload
  // const flag = await Database.get("PIOnProgress");
  // dLog("PIOnProgress . Flag - ", flag);

  //Run only when there is data in offlineImageData & there is no background service running

  console.log("offline adata ", offlineImageData);
  if (
    offlineImageData &&
    offlineImageData.length > 0 &&
    !BackgroundService.isRunning() &&
    flag
  ) {
    console.log(
      "[BACKGROUND] . startOfflineBackgroundUpload . offlineImageData ",
      JSON.stringify(offlineImageData, null, "  ")
    );

    const uploadPromise = createPromisifiedTask((resolve, reject) => {
      //start uploading background data
      // uploadOfflineDataInBackground(a, b, resolve);
      //check upload status
      let backgroundUploadRetryCount = 1;

      /**
       * calling checkUploadStatus after 1 min, which will ensure that
       * uploading of the images started by createActivityId.
       * previously it was resulting in duplication of documents
       * when checkUploadStatus was called instantly, it would find failed images and would try reuploading them
       * which parallely started uploading documents resulting in duplicates
       */

      setTimeout(() => {
        dLog("started checkUploadStatus after 10 sec");
        checkUploadStatus(backgroundUploadRetryCount, resolve);
      }, 10000);
    });

    const notificationConfig = createDefaultNotificationConfig(0);
    startBackgroundProcess(uploadPromise, notificationConfig);
  }
};

// export const BackgroundCreateActivityId = async () => {
//   let offlineImageData = await Database.get("PIOfflineVechicleData");

//   // TRUE - if user has reached to any progress screen then only we will start the upload
//   const flag = await Database.get("PIOnProgress");
//   dLog("PIOnProgress . Flag - ", flag);

//   //Run only when there is data in offlineImageData & there is no background service running
//   console.log("offline adata ", offlineImageData);
//   if (
//     offlineImageData &&
//     offlineImageData.dataTobeUploaded.length > 0 &&
//     !BackgroundService.isRunning() &&
//     flag
//   ) {
//     console.log(
//       "[BACKGROUND] . startOfflineBackgroundUpload . offlineImageData ",
//       JSON.stringify(offlineImageData, null, "  ")
//     );

//     const uploadPromise = createPromisifiedTask((resolve, reject) => {
//       //start uploading background data
//       uploadOfflineDataInBackground();
//       //check upload status
//       let backgroundUploadRetryCount = 1;

//       /**
//        * calling checkUploadStatus after 1 min, which will ensure that
//        * uploading of the images started by createActivityId.
//        * previously it was resulting in duplication of documents
//        * when checkUploadStatus was called instantly, it would find failed images and would try reuploading them
//        * which parallely started uploading documents resulting in duplicates
//        */

//       setTimeout(() => {
//         dLog("started checkUploadStatus after 1 min");
//         checkUploadStatus(backgroundUploadRetryCount, resolve);
//       }, 60000);
//     });

//     const notificationConfig = createDefaultNotificationConfig(0);
//     startBackgroundProcess(uploadPromise, notificationConfig);
//   }
// };

export const BackgroundUploadFile = (uri, documentImageName) => {
  /*
    Video is last document that uploads in every case  (4W,2W,CV)
    So start the video upload first once that is finished
    check if there are any remaining uploads
    if any start the upload 
    otherwise call document last


    [Flow]
    1. Upload VDO file
    2. Update the notification based on upload progress
    3. Keep a interval running that checks for upload status
    4. Once the Video is uploaded 
    5. Clear the interval at point no 3 & and call document last
    6. If the video failed to upload
    7. start everything that failed or in uploading state to reupload
    8. Keep a interval running that checks for upload status
    9. If Everything uploaded call document last
    10.Else reupload for three times

  */

  const uploadTask = createPromisifiedTask((resolve, reject) => {
    // File will start uploading
    UploadFile(
      uri,
      documentImageName,
      ".mp4",
      () => {
        // ON FAIL UPLOAD CALLBACK
      },
      () => {
        addSensorImageData(".mp4", true, documentImageName);
      },
      () => {
        addSensorImageData(".mp4", false, documentImageName);
      }
    );

    uploadOnlineDataInBackground();

    //Retry Count
    let backgroundUploadRetryCount = 1;
    //check upload status
    checkUploadStatus(backgroundUploadRetryCount, resolve);
  });

  const notificationConfig = createDefaultNotificationConfig(100);
  startBackgroundProcess(uploadTask, notificationConfig);
};

export const BackgroundUploadFile2W = async (uri, documentImageName) => {
  const uploadTask = createPromisifiedTask((resolve, reject) => {
    // File will start uploading
    UploadFile(
      uri,
      documentImageName,
      ".mp4",
      () => {
        // ON FAIL UPLOAD CALLBACK
      },
      () => {
        addSensorImageData(".mp4", true, documentImageName);
      },
      () => {
        addSensorImageData(".mp4", false, documentImageName);
      }
    );

    const flagCheckInterval = setInterval(async () => {
      const flag = await Database.get("PIOnProgress");
      dLog("inside interval flag - ", flag);
      if (flag) {
        clearInterval(flagCheckInterval);
        // uploadOnlineDataInBackground();
        //Retry Count
        let backgroundUploadRetryCount = 1;
        //check upload status
        checkUploadStatus(backgroundUploadRetryCount, resolve);
      }
    }, 1000);

    //add a edge case later
    //if user left the flow in the middle of the process
    //background process will keep on going
    //to stop it think of way
  });
  const notificationConfig = createDefaultNotificationConfig(100);
  startBackgroundProcess(uploadTask, notificationConfig);
};

export const BackgroundUploadFile2WOffline = async () => {
  const uploadTask = createPromisifiedTask((resolve, reject) => {
    // uploadOnlineDataInBackground();
    //Retry Count
    let backgroundUploadRetryCount = 1;
    //check upload status

    /**
     * calling checkUploadStatus after 1 min, which will ensure that
     * uploading of the images started by createActivityId.
     * previously it was resulting in duplication of documents
     * when checkUploadStatus was called instantly, it would find failed images and would try reuploading them
     * which parallely started uploading documents resulting in duplicates
     */

    setTimeout(() => {
      checkUploadStatus(backgroundUploadRetryCount, resolve);
    }, 60000);
  });
  const notificationConfig = createDefaultNotificationConfig(100);
  startBackgroundProcess(uploadTask, notificationConfig);
};

export const mockBackgroundProcess = () => {
  const uploadTask = createPromisifiedTask((resolve, reject) => {
    let progress = 1;
    const itr = setInterval(() => {
      dLog("mock progress", progress);
      updateNotificationContent(CONFIGS.BG_KILLED_VIDEO_UPLOAD, {
        max: 100,
        value: progress,
        indeterminate: false,
      });
      progress++;
    }, 1000);
  });
  const notificationConfig = createDefaultNotificationConfig(100);
  startBackgroundProcess(uploadTask, notificationConfig);
};

let sensorImageDetails = [];
const addSensorImageData = async (ext, ImageStatus, DocumentImageName) => {
  const { sensorDataInfo } = store.getState().sensorImageData;
  var PIRetryCount = await Database.get("PIRetryCount");
  var PIVechicleData = await Database.get("PIVechicleData");
  const PILocation = await Database.get("PILocation");

  var attemptCount = PIRetryCount?.retryCount + 1;
  var activityId = PIVechicleData?.activityId;
  var fileName = activityId + "_" + DocumentImageName + ext;
  const latitude = PILocation?.lat;
  const longitude = PILocation?.long;
  if (sensorDataInfo.length > 0) {
    sensorImageDetails = sensorDataInfo;
  } else {
    sensorImageDetails = [];
  }

  //adding sensor data
  sensorImageDetails.push({
    attemptCount: attemptCount,
    fileName: fileName,
    latitude: latitude,
    longitude: longitude,
    pose: DocumentImageName,
    success: ImageStatus,
    timestamp: new Date().getTime(),
  });
  store.dispatch({
    type: "SENSOR_DETAILS",
    payload: sensorImageDetails,
  });
};
