<template>
  <div class="MessageInputForm">메시지 입력</div>
  <div class="PublicTalk">
    <div>전체 메시지</div>
    <template v-if="messagePublic.length == 0">
      <div>메시지가 없습니다.</div>
    </template>
    <MessagePlate
      v-for="msg of messagePublic"
      :key="msg.id"
      :modelValue="msg"
      :generalID="generalID"
      :generalName="generalName"
      :nationID="nationID"
      :permissionLevel="permissionLevel"
    ></MessagePlate>
  </div>
  <div class="NationalTalk">
    <div>국가 메시지</div>
    <template v-if="messageNational.length == 0">
      <div>메시지가 없습니다.</div>
    </template>
  </div>
  <div class="PrivateTalk">
    <div>개인 메시지</div>
    <template v-if="messagePrivate.length == 0">
      <div>메시지가 없습니다.</div>
    </template>
  </div>
  <div class="DiplomacyTalk">
    <div>외교 메시지</div>
    <template v-if="messageDiplomacy.length == 0">
      <div>메시지가 없습니다.</div>
    </template>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, toRef, type Ref } from "vue";
import { delay } from "@/util/delay";
import { SammoAPI } from "@/SammoAPI";
import { isString } from "lodash";
import type { MsgItem, MsgResponse, MsgType } from "@/defs/API/Message";
import MessagePlate from "@/components/MessagePlate.vue";

const emit = defineEmits<{
  (event: "request-refresh"): void;
}>();

const props = defineProps<{
  generalID: number;
  generalName: string;
  nationID: number;
  permissionLevel: number;
}>();

const generalID = toRef(props, "generalID");
const generalName = toRef(props, "generalName");
const nationID = toRef(props, "nationID");
const permissionLevel = toRef(props, "permissionLevel");

onMounted(() => {
  console.log("MessagePanel mounted");
  console.log(props);
});

const lastSequence = ref(-1);

const initRefreshLimit = 5;
let refreshLimit = initRefreshLimit;
const refreshP: Set<Promise<boolean>> = new Set();
let lastRefreshDone = 0;
let refreshTimer: null | number = null;

const messageStorage = new Map<number, MsgItem>();
const messagePublic = ref<MsgItem[]>([]);
const messageNational = ref<MsgItem[]>([]);
const messagePrivate = ref<MsgItem[]>([]);
const messageDiplomacy = ref<MsgItem[]>([]);

const messageIndexedList: Record<MsgType, Ref<MsgItem[]>> = {
  public: messagePublic,
  national: messageNational,
  private: messagePrivate,
  diplomacy: messageDiplomacy,
};

function updateMsgResponse(response: MsgResponse) {
  if (!response.keepRecent) {
    messageStorage.clear();
    for (const msgList of Object.values(messageIndexedList)) {
      msgList.value.length = 0;
    }
  }

  if(response.generalName != generalName.value){
    emit("request-refresh");
    return;
  }
  if(response.nationID != nationID.value){
    emit("request-refresh");
    return;
  }

  lastSequence.value = Math.max(lastSequence.value, response.sequence);

  for (const msgType of Object.keys(messageIndexedList) as (keyof typeof messageIndexedList)[]) {
    const msgList = messageIndexedList[msgType];


    const newMsgList = response[msgType];
    console.log(msgType, msgList, newMsgList);
    if (newMsgList.length == 0) {
      continue;
    }

    //순서가 어떤 순서인지 모르니, 여기서 내림차순으로 맞춘다.
    newMsgList.sort((a, b) => b.id - a.id);

    if (msgList.value.length == 0) {
      msgList.value = newMsgList;
      continue;
    }

    //head test
    const filteredMsgList: MsgItem[] = [];

    for (const msg of newMsgList) {
      const oldMsg = messageStorage.get(msg.id);
      if (oldMsg !== undefined) {
        continue;
      }
      messageStorage.set(msg.id, msg);
      filteredMsgList.push(msg);
    }

    if (filteredMsgList.length == 0) {
      continue;
    }

    const msgHeadID = msgList.value[0].id;
    const newMsgTailID = filteredMsgList[filteredMsgList.length - 1].id;
    if (newMsgTailID > msgHeadID) {
      msgList.value = [...filteredMsgList, ...msgList.value];
      continue;
    }

    const msgTailID = msgList.value[msgList.value.length - 1].id;
    const newMsgHeadID = filteredMsgList[0].id;

    if (msgTailID > newMsgHeadID) {
      msgList.value.push(...filteredMsgList);
      continue;
    }

    //중간에 삽입되는 경우는 에러이다.
    console.error("중간 삽입 있음", msgType, newMsgList);
  }
}

function beginRefreshTimer() {
  if (refreshTimer) {
    clearInterval(refreshTimer);
    refreshTimer = null;
  }
  refreshTimer = window.setInterval(function () {
    const now = Date.now();
    if (lastRefreshDone + 5000 < now) {
      //만약 서버 응답이 없다면?

      if (refreshP.size > refreshLimit && refreshTimer) {
        clearInterval(refreshTimer);
        refreshTimer = null;
        alert("서버 응답이 없습니다. 새로고침을 해주세요.");
        return;
      }

      refreshP.add(tryRefresh());
    }
  }, 2500);
}

async function tryRefresh() {
  if (refreshP.size > 0) {
    await Promise.race([...refreshP, delay(500)]);
  }

  const waiterP = (async () => {
    let response: MsgResponse | undefined = undefined;
    try {
      response = await SammoAPI.Message.GetRecentMessage({
        sequence: lastSequence.value,
      });

      const now = Date.now();
      if (lastRefreshDone < now) {
        lastRefreshDone = now;
      }

    } catch (e) {
      if (isString(e)) {
        alert(e);
      }
      console.error(e);
    }

    if(!response){
      return false;
    }

    updateMsgResponse(response);

    return true;
  })();
  void waiterP.then((result) => {
    if (!result) {
      refreshLimit--;
    } else {
      refreshLimit = initRefreshLimit;
    }
    refreshP.delete(waiterP);
  });
  refreshP.add(waiterP);

  return waiterP;
}

defineExpose({
  tryRefresh,
});

onMounted(async () => {
  beginRefreshTimer();
  await tryRefresh();
});
</script>
