import { defineStore } from "pinia";
import { useQuasar } from "quasar";
import moment from "moment";

import http from "@/plugins/http";
import config from "@/app.config";

import { useCounterMixin } from "@/stores/mixin";

import type {
  DataBackup,
  BackUpRunning,
  Schedule,
} from "@/modules/04_system/interface/response/Main";

import type { ScheduleCreate } from "@/modules/04_system/interface/request/Main";
import { ref } from "vue";

const mixin = useCounterMixin();
const $q = useQuasar();
const { messageError, showLoader, hideLoader } = mixin;

export const useDataStore = defineStore("systemStore", () => {
  const dataBackUp = ref<DataBackup[]>([]);
  const dataSchedule = ref<Schedule[]>([]);
  const prevBackupRunTotal = ref<number>(-1);
  const backupRunTotal = ref<number>(0);

  const prevRestoreRunTotal = ref<number>(-1);
  const restoreRunTotal = ref<number>(0);

  const recordRestore = ref<Record<string, DataBackup>>({});

  let backupTimeoutId: NodeJS.Timeout | null = null; // Timeout สำหรับการสำรองข้อมูล
  let restoreTimeoutId: NodeJS.Timeout | null = null; // Timeout สำหรับการคืนค่า

  /**
   * ดึงข้อมูลรายการข้อมูลสำรอง
   */
  async function fetchListBackup() {
    try {
      showLoader();
      const res = await http.get(config.API.backup);

      if (!res) return false;
      if (res.status === 200) {
        dataBackUp.value = await res.data;
        dataBackUp.value = dataBackUp.value.map((item) => {
          return {
            ...item,
            status: "สำเร็จ",
          };
        });
        return res.status;
      }
    } finally {
      hideLoader();
    }
  }

  /**
   * สร้างข้อมูสำรอง
   */
  async function createBackUp() {
    showLoader();
    await http
      .post(config.API.backup + "/create")
      .then(async () => {
        await backupRunningList(fetchListBackup);
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /**
   * ลบรายการข้อมูลสำรอง
   * @param filename ชื้่อข้อมูลสำรอง
   */
  async function deleteBackUp(filename: string) {
    showLoader();
    await http
      .delete(config.API.backup + "/delete", {
        data: { name: filename },
      })
      .then(async (res) => {
        if (res.status < 400) {
          dataBackUp.value = dataBackUp.value.filter((item) => {
            if (item.name !== filename) return true;
            return false;
          });
        }
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /**
   * คืนค่ารายการข้อมูลสำรอง
   * @param filename ชื้่อข้อมูลสำรอง
   */
  async function restore(filename: string) {
    await http
      .post<string>(config.API.restore, {
        name: filename,
      })
      .then(async (res) => {
        const tempValue = dataBackUp.value.find((item) => {
          if (item.name === filename) {
            return true;
          }
        });

        if (tempValue) {
          recordRestore.value[res.data] = tempValue;
        }

        restoreRunningList(fetchListBackup);
      })
      .catch((err) => {
        messageError($q, err);
      });
  }

  /**
   * ทำการ BackUp ข้อมูสำรอง auto
   * @param cb
   */
  async function backupRunningList(cb: () => void) {
    // Clear timeout
    if (backupTimeoutId) {
      clearTimeout(backupTimeoutId);
      backupTimeoutId = null;
    }
    await http
      .get<BackUpRunning[]>(config.API.backup + "/backup-running-list")
      .then(async (res) => {
        backupRunTotal.value = res.data.length;

        if (backupRunTotal.value === 0) {
          if (prevBackupRunTotal.value !== -1) cb();
          prevBackupRunTotal.value = backupRunTotal.value;
          return;
        }

        if (prevBackupRunTotal.value !== backupRunTotal.value) {
          res.data.forEach((item) => {
            const index = dataBackUp.value.findIndex((data) => {
              if (data.name === item.created_at.toString()) return true;
            });

            if (index === -1) {
              dataBackUp.value.unshift({
                id: item.created_at.toString(),
                name: "-",
                databaseSize: 0,
                storageSize: 0,
                timestamp: item.created_at,
                status: item.running ? "running" : "success",
              });
            }
          });

          prevBackupRunTotal.value = backupRunTotal.value;
        }

        // ตั้งเวลาเรียกใหม่
        backupTimeoutId = setTimeout(() => {
          backupRunningList(cb);
        }, 3000);
      })
      .catch((err) => {
        messageError($q, err);
      });
  }

  /**
   * ทำการ คื่อต่า ข้อมูสำรอง  auto
   * @param cb
   */
  async function restoreRunningList(cb: () => void) {
    // Clear timeout
    if (restoreTimeoutId) {
      clearTimeout(restoreTimeoutId);
      restoreTimeoutId = null;
    }

    await http
      .get<BackUpRunning[]>(config.API.backup + "/restore-running-list")
      .then(async (res) => {
        restoreRunTotal.value = res.data.length;
        if (restoreRunTotal.value === 0) {
          cb();
          prevRestoreRunTotal.value = restoreRunTotal.value;
          return;
        }

        if (prevRestoreRunTotal.value !== restoreRunTotal.value) {
          for (const [key, value] of Object.entries(recordRestore.value)) {
            if (!res.data.find((v) => v.id === key))
              delete recordRestore.value[key];
            else value.status = "running";
          }

          prevRestoreRunTotal.value = restoreRunTotal.value;
        }

        // ตั้ง timeout
        restoreTimeoutId = setTimeout(() => {
          restoreRunningList(cb);
        }, 3000);
      })
      .catch((err) => {
        messageError($q, err);
      });
  }

  function getSize(size: number): string {
    if (size === undefined) return "Unknow size";

    const units = ["B", "KB", "MB", "GB", "TB"];

    let i = 0;
    let sizeNumber = typeof size === "string" ? parseFloat(size) : size;
    while (sizeNumber >= 1024 && i++ < units.length - 1) {
      sizeNumber /= 1024;
    }
    return sizeNumber.toFixed(2) + " " + units[i];
  }

  function convertCronToForm(schedule: string, typeReturn: string): string {
    let allValues = schedule.split(" ");

    if (typeReturn === "typeOfSchedule") {
      if (
        allValues[3].includes("*") &&
        allValues[4].includes("*") &&
        allValues[5].includes("*")
      ) {
        return `daily`;
      }
      if (
        allValues[3].includes("*") &&
        allValues[4].includes("*") &&
        !allValues[5].includes("*")
      ) {
        return `weekly`;
      }
      if (
        !allValues[3].includes("*") &&
        allValues[4].includes("*") &&
        allValues[5].includes("*")
      ) {
        return `monthly`;
      }
    }

    if (typeReturn === "time") {
      if (allValues[2].includes("/")) {
        console.log(allValues[2]);
        return "";
      } else {
        return `${allValues[2]}:${allValues[1]}`;
      }
    }

    if (typeReturn === "timeStartEvery") {
      return allValues[2].split("/")[1];
    }

    if (typeReturn === "date") {
      if (!allValues[3].includes("*")) {
        const tempValue = allValues[3].split(",").join(" ");

        return `${tempValue}`;
      }

      if (!allValues[5].includes("*")) {
        const tempValue = allValues[5].split(",").join(" ");
        return `${tempValue}`;
      }
    }

    return "";
  }

  /**
   * ดึงข้อมูลรายการคืนค่า
   */
  async function getSchedule() {
    showLoader();
    await http
      .get<Schedule[]>(config.API.backup + "/schedule")
      .then((res) => {
        dataSchedule.value = res.data.map((item) => {
          return {
            id: item.id,
            name: item.name,
            schedule: item.schedule,
            type: convertCronToForm(item.schedule, "typeOfSchedule") || "",
            time: convertCronToForm(item.schedule, "time") || "",
            date: convertCronToForm(item.schedule, "date") || "",
            timeStartEvery:
              convertCronToForm(item.schedule, "timeStartEvery") || "",
            startAt: moment(item.startAt)
              .utcOffset(7)
              .format("YYYY-MM-DD HH:mm"),
            enabled: item.enabled,
          };
        });
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /**
   * สร้างข้อมูลสำรอง
   * @param data  ข้อมูลตั้งเวลา
   */
  async function createSchedule(data: ScheduleCreate) {
    showLoader();
    await http
      .post(config.API.backup + "/schedule", {
        name: data.name,
        schedule: data.schedule,
        startAt: data.startAt !== undefined ? data.startAt : undefined,
      })
      .then(async (res) => {
        return res.data;
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /**
   * แก้ไขข้อมูลสำรอง
   * @param id id ที่ต้องการแก้ไข
   * @param data  ข้อมูลตั้งเวลา
   */
  async function editSchedule(id: string, data: ScheduleCreate) {
    showLoader();
    await http
      .put(config.API.backup + "/schedule/" + id, {
        startAt: data.startAt !== undefined ? data.startAt : undefined,
        enabled: data.enabled,
        schedule: data.schedule,
        name: data.name,
      })
      .then(async (res) => {
        return res.data;
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  async function toggleSchedule(id: string) {
    showLoader();
    await http
      .post(config.API.backup + "/schedule/" + id + "/toggle")
      .then(async (res) => {
        return res.data;
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /**
   * ลบข้อมูลสำรอง
   * @param id id ที่ต้องการลบ   */
  async function deleteSchedule(id: string) {
    showLoader();
    await http
      .delete(config.API.backup + "/schedule/" + id)
      .then(async () => {
        await fetchListBackup();
      })
      .catch((err) => {
        messageError($q, err);
      })
      .finally(() => {
        hideLoader();
      });
  }

  /** ฟังก์ชันหยุด polling สำหรับการสำรองข้อมูล */
  function stopBackupPolling() {
    if (backupTimeoutId) {
      clearTimeout(backupTimeoutId);
      backupTimeoutId = null;
    }
  }

  /** ฟังก์ชันหยุด polling สำหรับการคืนค่า */
  function stopRestorePolling() {
    if (restoreTimeoutId) {
      clearTimeout(restoreTimeoutId);
      restoreTimeoutId = null;
    }
  }

  /** ฟังก์ชันหยุดทั้งหมด */
  function stopAllPolling() {
    stopBackupPolling();
    stopRestorePolling();
  }

  return {
    dataBackUp,

    backupRunTotal,
    restoreRunTotal,

    prevBackupRunTotal,
    prevRestoreRunTotal,

    dataSchedule,

    fetchListBackup,
    createBackUp,
    restore,
    deleteBackUp,

    backupRunningList,
    restoreRunningList,
    stopAllPolling,

    getSize,

    getSchedule,
    createSchedule,
    editSchedule,
    deleteSchedule,

    toggleSchedule,
  };
});
