<template>
  <BContainer id="container" ref="container" :toast="{ root: true }">
    <TopBackBar :reloadable="true" title="부대 편성" @reload="refresh" />
    <div v-if="asyncReady && gameConstStore && me" id="troopList" class="bg0">
      <div v-for="[troopID, troop] of troopList" :key="troopID" class="troopItem">
        <div class="troopInfo">
          {{ troop.troopName }}<br />
          【 {{ gameConstStore.cityConst[troop.troopLeader.city].name }} 】
        </div>
        <div class="troopTurn">【턴】 {{ troop.turnTime.slice(14, 19) }}</div>
        <div class="troopLeaderIcon">
          <img height="64" width="64" :src="getIconPath(troop.troopLeader.imgsvr, troop.troopLeader.picture)" />
        </div>
        <div class="troopLeaderName">
          {{ troop.troopLeader.name }}
        </div>
        <div class="troopReservedCommand">
          <div v-for="(brief, idx) in troop.reservedCommandBrief" :key="idx">
            {{ `${idx + 1}: ${brief}` }}
          </div>
        </div>
        <div class="troopMembers">
          <template v-for="(member, idx) in troop.members" :key="member.no">
            <template v-if="idx != 0">, </template>
            <span
              v-if="member.troop == member.no"
              class="troopMember troopLeader"
              @mouseover="setPopup($event, member)"
              @mouseout="setPopup($event, undefined)"
            >
              {{ member.name }}
            </span>
            <span
              v-else-if="troop.troopLeader.city == member.city"
              class="troopMember"
              @mouseover="setPopup($event, member)"
              @mouseout="setPopup($event, undefined)"
            >
              {{ member.name }}
            </span>
            <span
              v-else
              class="troopMember troopDiffCityMemeber"
              @mouseover="setPopup($event, member)"
              @mouseout="setPopup($event, undefined)"
            >
              {{ member.name }} ({{ gameConstStore.cityConst[member.city].name }})
            </span>
          </template>
          ({{ troop.members.length }}명)
        </div>

        <div class="troopAction">
          <div
            v-if="tryTroopActionTarget.type === undefined || tryTroopActionTarget.targetTroop !== troop.troopID"
            class="actionButtons"
          >
            <BButton v-if="!me.troop" variant="primary" @click="joinTroop(troop.troopID)">부대 탑승</BButton>
            <BButton
              v-if="me.troop == troop.troopID"
              :variant="me.troop == me.no ? 'danger' : 'primary'"
              @click="exitTroop()"
              >{{ me.no == me.troop ? "부대 해산" : "부대 탈퇴" }}</BButton
            >
            <BButton v-if="me.troop == troop.troopID && me.no == me.troop" @click="openKickTroopMemberDialog(troop)"
              >부대원 추방...</BButton
            >
            <BButton v-if="myPermission >= 4" variant="info" @click="openChangeTroopNameDialog(troop)"
              >부대명 변경...</BButton
            >
          </div>
          <div v-else-if="tryTroopActionTarget.type === 'changeName'" class="subDialog">
            <div class="subTitle bg1 center"><span>부대명 변경</span></div>
            <div class="subForm d-grid">
              <BFormInput v-model="newTroopName" :trim="true" type="text" />
            </div>
            <div class="subBtnCancel d-grid">
              <BButton variant="secondary" @click="tryTroopActionTarget = { type: undefined, targetTroop: 0 }"
                >취소</BButton
              >
            </div>
            <div class="subBtnOK d-grid">
              <BButton variant="primary" @click="changeTroopName(troop)">변경</BButton>
            </div>
          </div>
          <div v-else-if="tryTroopActionTarget.type === 'kickMember'" class="subDialog">
            <div class="subTitle bg1 center" style="padding: 0.2em">부대명 추방</div>
            <div class="subForm d-grid">
              <BFormSelect v-model="kickTroopMemberID">
                <template v-for="member of troop.members" :key="member.no">
                  <BFormSelectOption v-if="member.no != troop.troopID" :value="member.no">
                    {{ member.name }}
                  </BFormSelectOption>
                </template>
              </BFormSelect>
            </div>
            <div class="subBtnCancel d-grid">
              <BButton variant="secondary" @click="tryTroopActionTarget = { type: undefined, targetTroop: 0 }"
                >취소</BButton
              >
            </div>
            <div class="subBtnOK d-grid">
              <BButton variant="primary" @click="kickTroopMember(troop)">추방</BButton>
            </div>
          </div>
        </div>
        <div class="filler"><span class="dummy"></span></div>
      </div>
    </div>
    <div v-if="asyncReady && gameConstStore && me" class="row additionalTroopOptions">
      <div v-if="me.troop == 0" class="col-6 col-md-3">
        <div class="row gx-0 makeNewTroop">
          <div class="bg1 col-12 center" style="font-size: 1.2em">부대 창설</div>
          <div class="troopNameField col-8 d-grid">
            <BFormInput v-model="newTroopName" :trim="true" type="text" />
          </div>
          <div class="col-4 d-grid">
            <BButton @click="makeTroop">부대 창설</BButton>
          </div>
        </div>
      </div>
    </div>
    <BottomBar />
    <div
      v-if="asyncReady && gameConstStore"
      id="generalPopup"
      :style="{ display: popupGeneralTarget ? 'block' : 'none', top: `${popupTop}px` }"
    >
      <div v-if="!popupGeneralTarget || !nationInfo"></div>
      <template v-else-if="popupGeneralTarget.st1">
        <GeneralBasicCard
          :general="popupGeneralTarget"
          :troopInfo="convBasicCardTroopInfo(popupGeneralTarget)"
          :nation="nationInfo"
          :turnTerm="turnTerm"
          :lastExecuted="lastExecuted"
        />
        <GeneralSupplementCard :general="popupGeneralTarget" :showCommandList="true" />
      </template>

      <GeneralLiteCard v-else :general="popupGeneralTarget" :nation="nationInfo" />
    </div>
  </BContainer>
</template>

<script setup lang="ts">
import TopBackBar from "@/components/TopBackBar.vue";
import BottomBar from "@/components/BottomBar.vue";
import { onMounted, provide, ref } from "vue";
import { SammoAPI } from "./SammoAPI";
import { BContainer, BButton, useToast, BFormInput, BFormSelect, BFormSelectOption } from "bootstrap-vue-next";
import { unwrap } from "./util/unwrap";
import { isString } from "lodash-es";
import type { GeneralListItem, GeneralListItemP1 } from "./defs/API/Nation";
import { merge2DArrToObjectArr } from "./util/merge2DArrToObjectArr";
import { convertIterableToMap } from "@/util/convertIterableToMap";
import { GameConstStore, getGameConstStore } from "./GameConstStore";
import { getIconPath } from "@/util/getIconPath";
import GeneralBasicCard from "./components/GeneralBasicCard.vue";
import type { NationStaticItem } from "./defs";
import GeneralLiteCard from "./components/GeneralLiteCard.vue";
import GeneralSupplementCard from "./components/GeneralSupplementCard.vue";
import { pick } from "./util/JosaUtil";
import { parseTime } from "./util/parseTime";
const toasts = unwrap(useToast());

const asyncReady = ref(false);
const gameConstStore = ref<GameConstStore>();
provide("gameConstStore", gameConstStore);
const storeP = getGameConstStore().then((store) => {
  gameConstStore.value = store;
});

void Promise.all([storeP]).then(() => {
  asyncReady.value = true;
});

const container = ref<HTMLElement>();

const popupGeneralTarget = ref<GeneralListItem>();
const popupTop = ref<number>(0);

function convBasicCardTroopInfo(general: GeneralListItemP1): { leader: GeneralListItemP1; name: string } | undefined {
  const troop = troopList.value.get(general.troop);
  if (!troop) {
    return undefined;
  }
  const troopLeader = troop.troopLeader;
  if (!troopLeader.st1) {
    return undefined;
  }
  return {
    leader: troopLeader,
    name: troop.troopName,
  };
}

function setPopup(e: MouseEvent, general: GeneralListItem | undefined) {
  if (general === undefined || !e.target) {
    popupTop.value = 0;
    popupGeneralTarget.value = undefined;
    return;
  }
  console.log("e", e);

  const target = e.target as HTMLElement;
  popupGeneralTarget.value = general;
  let parent = target.parentElement;
  console.log("parent", parent);
  while (parent !== null && !parent.classList.contains("troopMembers")) {
    parent = parent.parentElement;
  }

  if (parent === null) {
    popupTop.value = 0;
    popupGeneralTarget.value = undefined;
    return;
  }

  console.log(parent.offsetTop, parent.offsetHeight, parent);

  popupTop.value = parent.offsetTop + parent.offsetHeight;
}

type TroopInfo = {
  troopID: number;
  troopName: string;
  troopLeader: GeneralListItem;
  turnTime: string;
  reservedCommandBrief: string[];
  members: GeneralListItem[];
};

const me = ref<GeneralListItem>({} as GeneralListItem);
const myPermission = ref<0 | 1 | 2 | 3 | 4>(0);
const turnTerm = ref<number>(1);
const lastExecuted = ref<Date>(new Date());

const troopList = ref(new Map<number, TroopInfo>());
const generalList = ref(new Map<number, GeneralListItem>());
const nationInfo = ref<NationStaticItem>();

const newTroopName = ref("");
const kickTroopMemberID = ref(0);

type TroopAction = {
  type: "kickMember" | "changeName" | undefined;
  targetTroop: number;
};

const tryTroopActionTarget = ref<TroopAction>({
  type: undefined,
  targetTroop: 0,
});

async function refresh() {
  try {
    const generalListP = SammoAPI.Nation.GeneralList();
    const nationP = SammoAPI.Nation.GetNationInfo({});
    nationInfo.value = (await nationP).nation;
    const { column, list, permission, troops, env, myGeneralID } = await generalListP;
    turnTerm.value = env.turnterm;
    lastExecuted.value = parseTime(env.turntime);

    //빠른 턴 순서로 정렬되어있다.

    //XXX: 로직상 똑같은데....
    if (permission == 0) {
      const rawGeneralList = merge2DArrToObjectArr(column, list);
      generalList.value = convertIterableToMap(
        rawGeneralList.map((v) => {
          return { permission, st0: true, st1: false, st2: false, ...v };
        }),
        "no"
      );
    } else if (permission == 1) {
      const rawGeneralList = merge2DArrToObjectArr(column, list);
      generalList.value = convertIterableToMap(
        rawGeneralList.map((v) => {
          return { permission, st0: true, st1: true, st2: false, ...v };
        }),
        "no"
      );
    } else if ([2, 3, 4].includes(permission)) {
      const rawGeneralList = merge2DArrToObjectArr(column, list);
      generalList.value = convertIterableToMap(
        rawGeneralList.map((v) => {
          return { permission, st0: true, st1: true, st2: true, ...v };
        }),
        "no"
      );
    } else {
      throw `?? ${permission}`;
    }

    myPermission.value = permission;

    me.value = unwrap(generalList.value.get(myGeneralID));

    troopList.value = new Map();

    const sortedTroops = troops.sort((lhs, rhs) => {
      if (lhs.turntime < rhs.turntime) {
        return -1;
      }
      if (lhs.turntime > rhs.turntime) {
        return 1;
      }
      return lhs.id - rhs.id;
    });

    for (const { id: troopLeaderID, name: troopName, turntime: troopTurntime, reservedCommand } of sortedTroops) {
      if (!generalList.value.has(troopLeaderID)) {
        toasts.warning({
          title: "경고",
          body: `${troopName} 부대장(${troopLeaderID})이 아국 소속이 아닌 것 같습니다.`,
        });
        continue;
      }
      troopList.value.set(troopLeaderID, {
        troopID: troopLeaderID,
        troopName,
        troopLeader: unwrap(generalList.value.get(troopLeaderID)),
        turnTime: troopTurntime,
        reservedCommandBrief: reservedCommand,
        members: [],
      });
    }

    for (const general of generalList.value.values()) {
      const troopID = general.troop;
      if (!troopID) {
        continue;
      }
      const troop = troopList.value.get(troopID);
      if (troop === undefined) {
        console.error(`부대 소속 오류: ${general.no} in ${troopID}`);
        continue;
      }
      troop.members.push(general);
    }
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
    return;
  }
}

onMounted(() => {
  void refresh();
});

async function makeTroop() {
  const troopName = newTroopName.value;
  try {
    await SammoAPI.Troop.NewTroop({
      troopName,
    });
    newTroopName.value = "";
    toasts.info({
      title: "완료",
      body: `${troopName} 부대가 생성되었습니다.`,
    });
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
  }
  await refresh();
}

async function joinTroop(troopID: number) {
  try {
    await SammoAPI.Troop.JoinTroop({
      troopID,
    });
    toasts.info({
      title: "완료",
      body: ` ${troopList.value.get(troopID)?.troopName} 부대에 가입했습니다.`,
    });
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
  }
  await refresh();
}

async function exitTroop() {
  const isTroopLeader = me.value.troop == me.value.no;
  const troopName = troopList.value.get(me.value.troop)?.troopName ?? "??";

  if (isTroopLeader) {
    if (!confirm(`${troopName} 부대를 해산하겠습니까?`)) {
      return;
    }
  } else {
    if (!confirm(`${troopName} 부대에서 탈퇴하겠습니까?`)) {
      return;
    }
  }
  try {
    await SammoAPI.Troop.ExitTroop();

    if (isTroopLeader) {
      toasts.info({
        title: "완료",
        body: `부대를 해산했습니다.`,
      });
    } else {
      toasts.info({
        title: "완료",
        body: `부대에서 탈퇴했습니다.`,
      });
    }
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
  }
  await refresh();
}

function openChangeTroopNameDialog(troop: TroopInfo) {
  tryTroopActionTarget.value = {
    type: "changeName",
    targetTroop: troop.troopID,
  };
  newTroopName.value = troop.troopName;
}

async function changeTroopName(troop: TroopInfo) {
  const troopID = troop.troopID;
  const troopName = newTroopName.value;
  const oldTroopName = troop.troopName;
  const josaRo = pick(troopName, "로");
  if (!confirm(`${oldTroopName} 부대의 이름을 ${troopName}${josaRo} 바꾸시겠습니까?`)) {
    return;
  }
  try {
    await SammoAPI.Troop.SetTroopName({
      troopID,
      troopName,
    });

    toasts.info({
      title: "완료",
      body: `부대명을 변경했습니다.`,
    });
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
  }
  await refresh();
}

function openKickTroopMemberDialog(troop: TroopInfo) {
  tryTroopActionTarget.value = {
    type: "kickMember",
    targetTroop: troop.troopID,
  };
  for (const member of troop.members) {
    if (member.no == troop.troopID) {
      continue;
    }
    kickTroopMemberID.value = member.no;
    break;
  }
}

async function kickTroopMember(troop: TroopInfo) {
  const kickMember = generalList.value.get(kickTroopMemberID.value);
  if (kickMember === undefined) {
    toasts.danger({
      title: "오류",
      body: "잘못된 접근입니다.",
    });
    return;
  }
  const troopID = troop.troopID;
  const troopName = troop.troopName;

  const generalID = kickMember.no;
  const generalName = kickMember.name;
  const josaUl = pick(generalName, "을");
  if (!confirm(`${troopName} 부대에서 ${generalName}${josaUl} 추방하시겠습니까?`)) {
    return;
  }
  try {
    await SammoAPI.Troop.KickFromTroop({
      troopID,
      generalID,
    });

    toasts.info({
      title: "완료",
      body: `${generalName}${josaUl} 추방했습니다.`,
    });
  } catch (e) {
    if (isString(e)) {
      toasts.danger({
        title: "오류",
        body: e,
      });
    }
    console.error(e);
  }
  await refresh();
}
</script>

<style lang="scss" scoped>
@import "@scss/common/break_500px.scss";

#container {
  position: relative;
}

#generalPopup {
  position: absolute;
  width: 500px;
}

.additionalTroopOptions {
  margin-top: 1em;
}

.makeNewTroop {
  border: solid 1px gray;
}

.troopDiffCityMemeber {
  color: red;
}

.troopItem {
  display: grid;
  border-right: solid 1px gray;

  > div {
    border-top: solid 1px gray;
    border-left: solid 1px gray;
  }

  .troopInfo {
    grid-column: 1/3;
    grid-row: 1/2;
    display: grid;
    align-content: center;
    text-align: center;
  }

  .troopTurn {
    grid-column: 1/3;
    grid-row: 2/3;
    display: grid;
    align-content: center;
    justify-content: center;
  }

  .troopLeaderIcon {
    grid-column: 3/4;
    grid-row: 1/2;
    display: grid;
    align-content: center;
    justify-content: center;
  }

  .troopLeaderName {
    grid-column: 3/4;
    grid-row: 2/3;
    display: grid;
    align-items: center;
    justify-content: center;
  }

  .troopReservedCommand {
    grid-column: 4/5;
    grid-row: 1/3;
    font-size: 85%;
    text-align: left;
  }

  .troopAction {
    grid-column: 6/7;
    grid-row: 1/3;

    .btn {
      padding-top: 0.2em;
      padding-bottom: 0.2em;
    }
  }

  .troopMembers {
    text-align: left;
    padding: 0.5em 0.7em;
  }
}

@include media-1000px {
  #container {
    width: 1000px;
    margin: 0 auto;
    position: relative;
  }

  #generalPopup {
    left: 260px;
  }

  .troopItem {
    grid-template-rows: 65px 28px 34.5px;
    grid-template-columns: 65px 65px 130px 100px 1fr;

    .troopMembers {
      grid-column: 5/6;
      grid-row: 1/3;
    }

    &:last-of-type {
      border-bottom: solid 1px gray;
    }

    .filler {
      grid-column: 1/2;
      grid-row: 3/4;
      display: grid;
      align-content: center;
      justify-content: right;

      .dummy::after {
        content: "└";
        padding-right: 1.5ch;
      }
    }

    .troopAction {
      grid-column: 2/7;
      grid-row: 3/4;
      border-left: transparent;
      .actionButtons {
        display: grid;
        grid-template-columns: 110px 110px 110px;
        grid-template-rows: 33.5px;
      }
    }
  }

  .subDialog {
    display: grid;
    grid-template-columns: 90px 140px 50px 50px;

    .subTitle {
      display: grid;
      align-content: center;
    }
  }
}

@include media-500px {
  #container {
    width: 500px;
    margin: 0 auto;
    position: relative;
  }

  #generalPopup {
    left: 0;
  }

  .troopItem {
    grid-template-rows: 65px 28px auto;
    grid-template-columns: 65px 65px 130px 100px 0px 140px;

    .troopMembers {
      grid-column: 3/7;
      grid-row: 3/4;
    }

    &:last-of-type {
      .troopMembers {
        border-bottom: solid 1px gray;
      }
    }

    .filler {
      border-top: solid 1px gray;
      grid-column: 1/3;
      grid-row: 3/4;
    }
  }

  .actionButtons {
    display: grid;
  }

  .subDialog {
    display: grid;
    height: 100%;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;

    .subTitle,
    .subForm {
      display: grid;
      align-content: center;
      grid-column: 1/3;
    }
  }
}
</style>
