// The Lucia project.
// Copyright 2023-2026 DSP, inc.  All rights reserved.
// Authors:
//   chiayin.kuo@dsp.im (chiayin), 2023/1/31
//   imacat.yang@dsp.im (imacat), 2023/9/23
//   cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/** @module alertModal SweetAlert2 modal dialogs for user interactions. */

import Swal from "sweetalert2";
import { useAllMapDataStore } from "@/stores/allMapData";
import { useConformanceStore } from "@/stores/conformance";
import { useFilesStore } from "@/stores/files";
import { usePageAdminStore } from "@/stores/pageAdmin";
import { useModalStore } from "@/stores/modal";
import { escapeHtml } from "@/utils/escapeHtml.js";

const customClass = {
  container: "!z-[99999]",
  popup: "!w-[564px]",
  title: "!text-xl !font-semibold !mb-2",
  htmlContainer: "!text-sm !font-normal !h-full !mb-4 !leading-5",
  inputLabel: "!text-sm !font-normal",
  input:
    "!h-8 !text-sm !font-normal !shadow-inner !shadow-black !border-neutral-200",
  validationMessage: "!bg-neutral-10 !text-danger",
  confirmButton:
    "!inline-block !rounded-full !text-sm !font-medium !text-center !align-middle !transition-colors !duration-300 !px-5 !py-2 !w-[100px] !h-[40px]",
  cancelButton:
    "!inline-block !rounded-full !text-sm !font-medium !text-center !align-middle !transition-colors !duration-300 !px-5 !py-2 !w-[100px] !h-[40px] ",
};
/**
 * Shows a modal dialog to save a new filter with a user-provided name.
 *
 * @param {Function} addFilterId - Backend API function to create the filter.
 * @param {Function|null} [next=null] - Vue Router next() guard callback.
 * @returns {Promise<boolean>} True if the filter was saved, false otherwise.
 */
export async function saveFilter(addFilterId, next = null) {
  let fileName = "";
  const pageAdminStore = usePageAdminStore();

  const { value, isConfirmed } = await Swal.fire({
    title: "SAVE NEW FILTER",
    input: "text",
    inputPlaceholder: "Enter Filter Name.",
    inputValue: fileName,
    inputAttributes: {
      maxlength: 200,
    },
    inputValidator: (value) => {
      if (!value) return "You need to write something!";
      fileName = value;
    },
    icon: "info",
    iconHtml:
      '<span class="material-symbols-outlined !text-[58px]">cloud_upload</span>',
    iconColor: "#0099FF",
    reverseButtons: true,
    confirmButtonColor: "#0099FF",
    showCancelButton: true,
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
  });
  // Determine whether to redirect based on the return value
  if (isConfirmed) {
    // Save succeeded
    await addFilterId(fileName);
    // Show save complete notification
    if (value) {
      // Example of value: yes
      savedSuccessfully(value);
    }
    // Clear the input field
    fileName = "";
    return true;
  } else {
    // Clicked cancel or outside the dialog; save failed.
    pageAdminStore.keepPreviousPage();

    // Not every time we have nontrivial next value
    if (next !== null) {
      next(false);
    }
    return false;
  }
}
/**
 * Shows a timed success notification after a file has been saved.
 *
 * @param {string} value - The name of the saved file.
 * @returns {Promise<void>}
 */
export async function savedSuccessfully(value = "") {
  await Swal.fire({
    title: "SAVE COMPLETE",
    html: `<span class="text-primary">${escapeHtml(value)}</span> has been saved in Lucia.`,
    timer: 3000, // Auto-close after 3 seconds
    showConfirmButton: false,
    icon: "success",
    iconColor: "#0099FF",
    customClass: customClass,
  });
}
/**
 * Prompts the user to save unsaved filter changes before leaving the
 * Map page. Handles confirm (save), cancel (discard), and backdrop
 * (stay) scenarios.
 *
 * @param {Function} next - Vue Router next() guard callback.
 * @param {Function} addFilterId - Backend API function to create the filter.
 * @param {string} toPath - The destination route path.
 * @param {Function} [logOut] - Optional logout function to call instead
 *   of navigating.
 * @returns {Promise<void>}
 */
export async function leaveFilter(next, addFilterId, toPath, logOut) {
  const allMapDataStore = useAllMapDataStore();
  const pageAdminStore = usePageAdminStore();

  const result = await Swal.fire({
    title: "SAVE YOUR FILTER?",
    html: "If you want to continue using this filter in any other page, please select [Yes].",
    icon: "warning",
    iconColor: "#FF3366",
    reverseButtons: true,
    confirmButtonText: "Yes",
    confirmButtonColor: "#FF3366",
    showCancelButton: true,
    cancelButtonText: "No",
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
  });

  if (result.isConfirmed) {
    if (allMapDataStore.createFilterId) {
      await allMapDataStore.updateFilter();
      if (allMapDataStore.isUpdateFilter) {
        await savedSuccessfully(allMapDataStore.filterName);
      }
    } else {
      // Dangerous, here shows a modal
      await saveFilter(addFilterId, next);
    }

    logOut ? logOut() : next(toPath);
  } else if (result.dismiss === "cancel") {
    // console.log('popup cancel case', );
    // Handle page admin issue
    // console.log("usePageAdminStore.activePage", usePageAdminStore.activePage);
    pageAdminStore.keepPreviousPage();

    allMapDataStore.tempFilterId = null;
    logOut ? logOut() : next(toPath);
  } else if (result.dismiss === "backdrop") {
    // console.log('popup backdrop case', );
    // Handle page admin issue
    // console.log("usePageAdminStore.activePage", usePageAdminStore.activePage);
    pageAdminStore.keepPreviousPage();

    if (!logOut) {
      next(false);
    }
  }
}
/**
 * Shows a modal dialog to save a new conformance rule with a
 * user-provided name.
 *
 * @param {Function} addConformanceCreateCheckId - Backend API function
 *   to create the conformance check.
 * @returns {Promise<boolean>} True if the rule was saved, false otherwise.
 */
export async function saveConformance(addConformanceCreateCheckId) {
  let fileName = "";
  const { value, isConfirmed } = await Swal.fire({
    title: "SAVE NEW RULE",
    input: "text",
    inputPlaceholder: "Enter Rule Name.",
    inputValue: fileName,
    inputAttributes: {
      maxlength: 200,
    },
    inputValidator: (value) => {
      if (!value) return "You need to write something!";
      fileName = value;
    },
    icon: "info",
    iconHtml:
      '<span class="material-symbols-outlined !text-[58px]">cloud_upload</span>',
    iconColor: "#0099FF",
    reverseButtons: true,
    confirmButtonColor: "#0099FF",
    showCancelButton: true,
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
  });
  // Determine whether to redirect based on the return value
  if (isConfirmed) {
    // Save succeeded
    await addConformanceCreateCheckId(fileName);
    // Show save complete notification
    if (value) savedSuccessfully(value);
    // Clear the input field
    fileName = "";
    return true;
  } else {
    // Clicked cancel or outside the dialog; save failed.
    return false;
  }
}
/**
 * Prompts the user to save unsaved conformance rule changes before
 * leaving the Conformance page. Delegates to helper functions for
 * confirm, cancel, and backdrop scenarios.
 *
 * @param {Function} next - Vue Router next() guard callback.
 * @param {Function} addConformanceCreateCheckId - Backend API function
 *   to create the conformance check.
 * @param {string} toPath - The destination route path.
 * @param {Function} [logOut] - Optional logout function.
 * @returns {Promise<void>}
 */
export async function leaveConformance(
  next,
  addConformanceCreateCheckId,
  toPath,
  logOut,
) {
  const conformanceStore = useConformanceStore();
  const result = await showConfirmationDialog();

  if (result.isConfirmed) {
    await handleConfirmed(conformanceStore, addConformanceCreateCheckId);
  } else {
    await handleDismiss(result.dismiss, conformanceStore, next, toPath, logOut);
  }
}
/**
 * Displays the "SAVE YOUR RULE?" confirmation dialog.
 * @returns {Promise<Object>} The SweetAlert2 result object.
 */
async function showConfirmationDialog() {
  return Swal.fire({
    title: "SAVE YOUR RULE?",
    icon: "warning",
    iconColor: "#FF3366",
    reverseButtons: true,
    confirmButtonText: "Yes",
    confirmButtonColor: "#FF3366",
    showCancelButton: true,
    cancelButtonText: "No",
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
  });
}

/**
 * Handles the confirmed save action for conformance rules.
 * @param {Object} conformanceStore - The conformance Pinia store.
 * @param {Function} addConformanceCreateCheckId - API function to create check.
 * @returns {Promise<void>}
 */
async function handleConfirmed(conformanceStore, addConformanceCreateCheckId) {
  if (
    conformanceStore.conformanceFilterCreateCheckId ||
    conformanceStore.conformanceLogCreateCheckId
  ) {
    await conformanceStore.updateConformance();
    if (conformanceStore.isUpdateConformance) {
      await savedSuccessfully(conformanceStore.conformanceFileName);
    }
  } else {
    await saveConformance(addConformanceCreateCheckId);
  }
}

/**
 * Handles dismiss actions (cancel or backdrop click) for conformance modals.
 * @param {string} dismissType - The SweetAlert2 dismiss reason.
 * @param {Object} conformanceStore - The conformance Pinia store.
 * @param {Function} next - Vue Router next() guard callback.
 * @param {string} toPath - The destination route path.
 * @param {Function} [logOut] - Optional logout function.
 * @returns {Promise<void>}
 */
async function handleDismiss(
  dismissType,
  conformanceStore,
  next,
  toPath,
  logOut,
) {
  switch (dismissType) {
    case "cancel":
      resetTempCheckId(conformanceStore);
      logOut ? logOut() : next(toPath);
      break;
    case "backdrop":
      if (!logOut) {
        next(false);
      }
      break;
    default:
      break;
  }
}

/**
 * Resets temporary conformance check IDs to null.
 * @param {Object} conformanceStore - The conformance Pinia store.
 */
function resetTempCheckId(conformanceStore) {
  conformanceStore.conformanceFilterTempCheckId = null;
  conformanceStore.conformanceLogTempCheckId = null;
}

/**
 * Shows an error modal for the first stage of upload validation failure.
 *
 * @param {string} failureType - The error type from the backend (e.g.
 *   "encoding", "insufficient_columns", "empty", "name_suffix", "mime_type").
 * @param {string} failureMsg - The raw error message from the backend.
 * @param {number} [failureLoc] - The row number where the error occurred.
 * @returns {Promise<void>}
 */
export async function uploadFailedFirst(failureType, failureMsg, failureLoc) {
  // msg: 'not in UTF-8' | 'insufficient columns' | 'the csv file is empty' | 'the filename does not ends with .csv' | 'not a CSV file'
  // type: 'encoding' | 'insufficient_columns' | 'empty' | 'name_suffix' | mime_type
  let value = "";
  switch (failureType) {
    case "size":
      value = "File size exceeds 90MB.";
      break;
    case "encoding":
      value = `Please use UTF-8 for character encoding: (Row #${failureLoc})`;
      break;
    case "insufficient_columns":
      value = "Need at least five columns of data.";
      break;
    case "empty":
      value = "Need at least one record of data.";
      break;
    case "name_suffix":
    case "mime_type":
      value = "File is not in csv format.";
      break;
    default:
      value = escapeHtml(failureMsg);
      break;
  }
  await Swal.fire({
    title: "IMPORT FAILED",
    html: value,
    timer: 3000, // Auto-close after 3 seconds
    showConfirmButton: false,
    icon: "error",
    iconColor: "#FF3366",
    customClass: customClass,
  });
}
/**
 * Shows an error modal for the second stage of upload validation failure,
 * listing individual row-level errors.
 *
 * @param {Array<{type: string, loc: Array, input: string}>} detail -
 *   Array of error detail objects from the backend.
 * @returns {Promise<void>}
 */
export async function uploadFailedSecond(detail) {
  let srt = "";
  let manySrt = "";

  detail.forEach((i) => {
    let content = "";
    let key = "";
    switch (i.type) {
      case "too_many":
        manySrt = "There are more errors.";
        break;
      case "unrecognized":
        content = `<li>Data unrecognizable in Status Column: (Row #${i.loc?.[1] ?? "?"}, "${escapeHtml(i.input)}")</li>`;
        break;
      case "malformed":
        content = `<li>Data malformed in Timestamp Column: (Row #${i.loc?.[1] ?? "?"}, "${escapeHtml(i.input)}")</li>`;
        break;
      case "missing":
        switch (i.loc?.[2]) {
          case "case id":
            key = "Case ID";
            break;
          case "timestamp":
            key = "Timestamp";
            break;
          case "name":
            key = "Activity";
            break;
          case "instance":
            key = "Activity Instance ID";
            break;
          case "status":
            key = "Status";
            break;
          default:
            key = escapeHtml(String(i.loc?.[2] ?? ""));
            break;
        }
        content = `<li>Data missing in ${key} Column: (Row #${i.loc?.[1] ?? "?"})</li>`;
        break;
    }
    srt += content;
  });
  await Swal.fire({
    title: "IMPORT FAILED",
    html: `<div class="text-left mx-3 space-y-1"><p>Error(s) detected:</p><ul class="list-disc ml-6">${srt}</ul><p>${manySrt} Please check.</p></div>`,
    timer: 3000, // Auto-close after 3 seconds
    showConfirmButton: false,
    icon: "error",
    iconColor: "#FF3366",
    customClass: customClass,
  });
  srt = "";
}
/**
 * Shows a timed success notification after a file upload completes.
 * @returns {Promise<void>}
 */
export async function uploadSuccess() {
  await Swal.fire({
    title: "IMPORT COMPLETED",
    timer: 3000, // Auto-close after 3 seconds
    showConfirmButton: false,
    icon: "success",
    iconColor: "#0099FF",
    customClass: customClass,
  });
}
/**
 * Shows a confirmation dialog before uploading a file. Proceeds with
 * the upload only if the user confirms.
 *
 * @param {Object} fetchData - The upload request payload for the backend.
 * @returns {Promise<void>}
 */
export async function uploadConfirm(fetchData) {
  const filesStore = useFilesStore();
  const result = await Swal.fire({
    title: "ARE YOU SURE?",
    html: "After importing, you won’t be able to modify labels.",
    icon: "warning",
    iconColor: "#FF3366",
    reverseButtons: true,
    confirmButtonText: "Yes",
    confirmButtonColor: "#FF3366",
    showCancelButton: true,
    cancelButtonText: "No",
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
  });

  if (result.isConfirmed) {
    filesStore.uploadLog(fetchData);
  }
}
/**
 * Shows a non-dismissable loading spinner during file upload.
 * @returns {Promise<void>}
 */
export async function uploadloader() {
  await Swal.fire({
    html: '<span class="loaderBar mt-7"></span>',
    showConfirmButton: false,
    allowOutsideClick: false,
    customClass: customClass,
  });
}
/**
 * Shows a modal dialog for renaming a file.
 *
 * @param {Function} rename - Backend API function to rename the file.
 * @param {string} type - The file type (e.g. "log", "filter").
 * @param {number} id - The file ID.
 * @param {string} baseName - The current file name.
 * @returns {Promise<void>}
 */
export async function renameModal(rename, type, id, baseName) {
  const fileName = baseName;
  const { value, isConfirmed } = await Swal.fire({
    title: "RENAME",
    input: "text",
    inputPlaceholder: "Enter File Name.",
    inputValue: fileName,
    inputAttributes: {
      maxlength: 200,
    },
    icon: "info",
    iconHtml:
      '<span class="material-symbols-outlined !text-[58px]">edit_square</span>',
    iconColor: "#0099FF",
    reverseButtons: true,
    confirmButtonColor: "#0099FF",
    showCancelButton: true,
    cancelButtonColor: "#94a3b8",
    customClass: customClass,
    didOpen: () => {
      const confirmButton = Swal.getConfirmButton();
      const inputField = Swal.getInput();

      inputField.addEventListener("input", function () {
        if (inputField.value.trim()) {
          confirmButton.classList.remove("disable-hover");
          confirmButton.disabled = false;
        } else {
          confirmButton.classList.add("disable-hover");
          confirmButton.disabled = true;
        }
      });
    },
  });

  // Rename succeeded
  if (isConfirmed) await rename(type, id, value);
  // Clear the field: fileName = ''
}
/**
 * Shows a confirmation dialog for deleting a file and its dependents.
 *
 * @param {string} files - HTML string listing dependent files to be deleted.
 * @param {string} type - The file type (e.g. "log", "filter").
 * @param {number} id - The file ID.
 * @param {string} name - The file name.
 * @returns {Promise<void>}
 */
export async function deleteFileModal(files, type, id, name) {
  const filesStore = useFilesStore();

  const safeName = escapeHtml(name);
  const htmlText =
    files.length === 0
      ? `Do you really want to delete <span class="text-primary">${safeName}</span>?`
      : `<div class="text-left mx-4 space-y-1"><p class="mb-2">Do you really want to delete <span class="text-primary">${safeName}</span>?</p><p>The following dependent file(s) will also be deleted:</p><ul class="list-disc ml-6">${files}</ul></div>`;

  const deleteCustomClass = { ...customClass };
  deleteCustomClass.confirmButton =
    "!inline-block !rounded-full !text-sm !font-medium !text-center !align-middle !transition-colors !duration-300 !px-5 !py-2 !w-[100px] !h-[40px] !text-danger !bg-neutral-10 !border !border-danger";

  const result = await Swal.fire({
    title: "CONFIRM DELETION",
    html: htmlText,
    icon: "warning",
    iconColor: "#FF3366",
    reverseButtons: true,
    confirmButtonColor: "#ffffff",
    showCancelButton: true,
    cancelButtonColor: "#FF3366",
    customClass: deleteCustomClass,
    didOpen: () => {
      const confirmButton = Swal.getConfirmButton();

      confirmButton.style.border = "1px solid #FF3366";
    },
  });

  if (result.isConfirmed) {
    filesStore.deleteFile(type, id);
  }
}
/**
 * Shows a timed success notification after file deletion.
 * @returns {Promise<void>}
 */
export async function deleteSuccess() {
  await Swal.fire({
    title: "FILE(S) DELETED",
    timer: 3000, // Auto-close after 3 seconds
    showConfirmButton: false,
    icon: "success",
    iconColor: "#0099FF",
    customClass: customClass,
  });
}
/**
 * Shows an informational modal about files deleted by other users,
 * then records the deletions and refreshes the file list.
 *
 * @param {string} files - HTML string listing the deleted files.
 * @param {Array<{id: number}>} reallyDeleteData - Array of deleted file
 *   objects with their IDs.
 * @returns {Promise<void>}
 */
export async function reallyDeleteInformation(files, reallyDeleteData) {
  const filesStore = useFilesStore();
  const deleteCustomClass = { ...customClass };
  const htmlText = `<div class="text-left mx-4 space-y-1"><p>The following file(s) have been deleted by other user(s):</p><ul class="list-disc ml-6">${files}</ul></div>`;

  deleteCustomClass.confirmButton =
    "!inline-block !rounded-full !text-sm !font-medium !text-center !align-middle !transition-colors !duration-300 !px-5 !py-2 !w-[100px] !h-[40px] !text-primary !bg-neutral-10 !border !border-primary";
  deleteCustomClass.cancelButton = null;
  await Swal.fire({
    title: "FILE(S) DELETED BY OTHER USER(S)",
    html: htmlText,
    icon: "info",
    iconColor: "#0099FF",
    customClass: deleteCustomClass,
    confirmButtonColor: "#ffffff",
    didOpen: () => {
      const confirmButton = Swal.getConfirmButton();

      confirmButton.style.border = "1px solid #0099FF";
    },
  });
  await Promise.all(
    reallyDeleteData.map((file) => filesStore.deletionRecord(file.id)),
  );
  await filesStore.fetchAllFiles();
}

/**
 * Shows a reminder modal when the user leaves the account management
 * page with unsaved edits.
 * @returns {Promise<void>}
 */
export async function leaveAccountManagementToRemind() {
  const modalStore = useModalStore();
  const result = await Swal.fire({
    title: "SAVE YOUR EDIT?",
    icon: "info",
    showCancelButton: true,
    didOpen: () => {
      const confirmButton = Swal.getConfirmButton();

      confirmButton.style.border = "1px solid #0099FF";
    },
  });
  if (result.isConfirmed) {
    return;
  } else {
    modalStore.openModal();
  }
}
