import { defineStore } from "pinia";
import { ref } from "vue";
import { io } from "socket.io-client";
import http from "@/plugins/http";
import config from "@/app.config";

import { useCounterMixin } from "@/stores/mixin";
import type {
  SupportMessageResponse,
  SupportIssueResponse,
  SupportStatusUser,
  SupportMessageStatus,
  SupportIssueCategoryResponse,
} from "@/modules/00_support/interface/index/Main";
import { getToken, tokenParsed } from "@/plugins/auth";

export const useSupportStore = defineStore("supportServiceStore", async () => {
  const { showLoader, hideLoader } = useCounterMixin();
  const userId = ref<string | undefined>("");
  const issue = ref<SupportIssueResponse>();
  const message = ref<SupportMessageResponse>();
  const messageStatus = ref<SupportMessageStatus>();
  const userStatus = ref<SupportStatusUser[]>([]);
  const currentIssue = ref<string>("");
  const currentTitle = ref<string>("");
  const currentCategoryId = ref<string>("");
  const correntStatusIssue = ref<"new" | "ongoing" | "resolved">("new");
  const currentTotalMessage = ref<number>();
  const currentPage = ref<number>();
  const scrollContainer = ref();
  const currentPageIssue = ref<number>();
  const currentTotalIssue = ref<number>();
  const currentCategory = ref<string>();
  const createdByUserId = ref<string>("");
  const createdByUserName = ref<string>("");

  const rowsCategory = ref<SupportIssueCategoryResponse>();

  function scrollToEnd(position: Number = 1) {
    setTimeout(() => {
      scrollContainer.value?.setScrollPercentage("vertical", position);
    }, 150);
  }

  const token = await getToken();
  const socket = io(config.API.supportSocket, {
    auth: { token: token },
    autoConnect: false,
    path: "/api/v1/support/socket/",
  });

  socket.on("users", (data: SupportStatusUser[]) => {
    userStatus.value = data;
  });

  socket.on("online", async (r) => {
    const user = await tokenParsed();
    userId.value = user.subject;

    userStatus.value.push({
      socketId: r.socketId,
      userId: r.userId,
      name: r.name,
      role: r.role,
    });
  });

  socket.on("offline", (socketId: string) => {
    if (socketId === socket.id) return;
    userStatus.value = userStatus.value.filter((v) => v.socketId !== socketId);
  });

  socket.on("notify-message", (r) => {
    if (issue.value) {
      issue.value.result = issue.value.result.map((v) => {
        if (v.id === r.issueId) {
          v.unreadCount++;
          v.lastMessage = r.content;
          v.updatedAt = r.updatedAt;
        }
        if (currentIssue.value === r.issueId) {
          v.unreadCount = 0;
        }
        return v;
      });
    }
  });

  socket.on("read", (r) => {
    if (messageStatus.value) {
      messageStatus.value.result = messageStatus.value.result.map((v) => {
        if (v.fromUserId === r.fromUserId) return r;
        return v;
      });
    }
  });

  socket.on("message", (r) => {
    message.value?.result.message.push(r);

    if (issue.value) {
      issue.value.result = issue.value.result.map((v) => {
        if (v.id === r.issueId) {
          v.lastMessage = r.content;
          v.updatedAt = r.updatedAt;
        }
        return v;
      });
    }

    socket.emit("mark-read", { issueId: currentIssue.value });
    scrollToEnd();
  });

  function sendMessage(content: string, to: string) {
    socket.emit("message", { to, content });
    scrollToEnd();
  }

  async function fetchMessageStatus(issueId: string) {
    const res = await http
      .get(config.API.supportMessageStatus(issueId))
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {});

    if (res && res.data) {
      messageStatus.value = res.data;
    }
  }

  async function loadMessage(page: number) {
    const res = await http
      .get(`${config.API.supportMessage(currentIssue.value)}?page=${page}`)
      .catch((err) => {
        console.log(err);
      });

    if (res && res.data) {
      message.value?.result.message.unshift(...res.data.result.message);
      currentPage.value = res.data.page;
    }
  }

  async function fetchMessage(issueId: string) {
    showLoader();
    const res = await http
      .get(config.API.supportMessage(issueId))
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res && res.data) {
      message.value = await res.data;
      message.value?.result.message.reverse();
      currentPage.value = res.data.page;
      currentTotalMessage.value = res.data.total;
      socket.emit("join-issue", { issueId });
      socket.emit("mark-read", { issueId });
      scrollToEnd();
    }
  }

  async function ChangeStatusIssue(
    issueId: string,
    title: string,
    categoryId: string,
    status: "new" | "ongoing" | "resolved"
  ) {
    showLoader();
    const requestBody = {
      title: title,
      categoryId: categoryId,
      status: status,
    };

    const res = await http
      .patch(config.API.supportIssueChangeStatus(issueId), requestBody)
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });
    if (res) {
      fetchIssue();
      correntStatusIssue.value = status;
    }
  }

  async function fetchIssue(page: number = 1) {
    showLoader();
    const res = await http
      .get(`${config.API.supportIssue}?page=${page}&pageSize=30`)
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res && res.data) {
      issue.value = res.data;
      currentPageIssue.value = res.data.page;
      currentTotalIssue.value = res.data.total;
    }
  }

  async function searchIssue(input: string) {
    showLoader();
    const res = await http
      .get(config.API.supportSearchIssue(input))
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res && res.data) {
      issue.value = res.data;
      currentPageIssue.value = res.data.page;
      currentTotalIssue.value = res.data.total;
    }
  }

  async function newCategory(name: string) {
    showLoader();
    const res = await http
      .post(config.API.supportCategory, {
        name: name,
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res) {
      fetchCategory();
    }
  }

  async function fetchCategory() {
    showLoader();
    const res = await http
      .get(config.API.supportCategory)
      .catch((err) => {
        console.log(err);
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });
    if (res && res.data) {
      rowsCategory.value = res.data;
    }
  }

  async function deleteCategory(CategoryId: string) {
    showLoader();
    const res = await http
      .delete(config.API.supportCategoryAction(CategoryId))
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res) {
      fetchCategory();
    }
  }

  async function editCategory(CategoryId: string, name: string) {
    showLoader();
    const res = await http
      .patch(config.API.supportCategoryAction(CategoryId), {
        name: name,
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        hideLoader();
      });

    if (res) {
      fetchCategory();
    }
  }

  return {
    userId,
    issue,
    message,
    scrollContainer,
    currentIssue,
    currentTitle,
    socket,
    messageStatus,
    currentTotalMessage,
    currentPage,
    currentPageIssue,
    currentTotalIssue,
    currentCategoryId,
    correntStatusIssue,
    currentCategory,
    rowsCategory,
    userStatus,
    createdByUserId,
    createdByUserName,
    fetchIssue,
    fetchMessage,
    fetchMessageStatus,
    sendMessage,
    scrollToEnd,
    loadMessage,
    ChangeStatusIssue,
    newCategory,
    fetchCategory,
    deleteCategory,
    editCategory,
    searchIssue,
  };
});
