<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { useTokenStore } from '@/stores/token';
import MessageBox from '@/components/MessageBox.vue';
import {
  addOwn as apiCollectionAddOwn,
  getFullOwn as apiCollectionGetFullOwn,
  getSharing as apiCollectionGetSharing,
  getDetailOwn as apiCollectionGetDetailOwn,
  type CollectionRow,
  deleteOwn as apiCollectionDeleteOwn,
  updateOwn as apiCollectionUpdateOwn,
  addSharing as apiCollectionAddSharing,
  deleteSharing as apiCollectionDeleteSharing
} from '@/api/collection';
import OwnedItem from '@/components/collection/OwnedItem.vue';
import SharingItem from '@/components/collection/SharingItem.vue';

const ownedItems = ref<Map<string, CollectionRow>>(new Map());
const sharingItems = ref<string[]>([]);
const sharingItemUuid = ref<string | null>(null);
const isSharingItem = computed(() => {
  return typeof sharingItemUuid.value === 'string';
})
const pendingOwnedItemName = ref<string>("");
const pendingSharingItemUsername = ref<string>("");

const token = useTokenStore();
const messagebox = ref<InstanceType<typeof MessageBox>>();

onMounted(async () => {
  await refreshOwnedItem();
})

const refreshOwnedItem = async () => {
  // clean owned items
  ownedItems.value.clear();

  // Fetch data
  let rv = await apiCollectionGetFullOwn(token.currentToken);
  if (typeof rv === 'undefined') {
    console.error("fail to fetch owned collection");
    return;
  }
  // Add into dict for rendering
  for (let item of rv) {
    ownedItems.value.set(item[0], item);
  }

  // clean sharing status
  sharingItemUuid.value = null;
  await refreshSharingItem();
}

const addOwnedItem = async () => {
  let new_name = pendingOwnedItemName.value;
  if (new_name === '') {
    return
  }

  // first add it
  let rv = await apiCollectionAddOwn(token.currentToken, new_name);
  if (typeof rv === 'undefined') {
    messagebox.value?.show("An add operation failed. It may caused by wrong arguments. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // second get its detail
  let rv2 = await apiCollectionGetDetailOwn(token.currentToken, rv);
  if (typeof rv2 === 'undefined') {
    messagebox.value?.show("A get operation failed. It may caused by server internal error or your limited permission. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // render to list
  ownedItems.value.set(rv2[0], rv2);
}

const deleteOwnedItem = async (uuid: string) => {
  let rv = await apiCollectionDeleteOwn(token.currentToken, uuid, ownedItems.value.get(uuid)![2]);
  if (rv) {
    messagebox.value?.show("A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // remove from rendered list
  ownedItems.value.delete(uuid);

  // if we are editing sharing target of this item,
  // we should escape this status
  if (sharingItemUuid.value === uuid) {
    sharingItemUuid.value = null;
    await refreshSharingItem();
  }
}

const shareOwnedItem = async (uuid: string) => {
  // if there is no editing sharing target, set it.
  // otherwise override it or toggle it according to its old value.
  let old_value = sharingItemUuid.value;
  if (typeof old_value === 'string') {
    if (old_value === uuid) {
      sharingItemUuid.value = null;
    } else {
      sharingItemUuid.value = uuid;
    }
  } else {
    sharingItemUuid.value = uuid;
  }
  // refresh sharing list
  await refreshSharingItem();
}

const updateOwnedItem = async (uuid: string, name: string) => {
  let lastChange = ownedItems.value.get(uuid)![2];
  let rv = await apiCollectionUpdateOwn(token.currentToken, uuid, name, lastChange);
  if (typeof rv === 'undefined') {
    messagebox.value?.show("An update operation failed. It may caused by wrong arguments or lost target. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // return value is new lastChange, so we update it.
  let row = ownedItems.value.get(uuid)!;
  row[1] = name;
  row[2] = rv;

  // if current item is sharing, update it at the same time
  if (sharingItemUuid.value === uuid) {
    await refreshSharingItem();
  }
}

const refreshSharingItem = async () => {
  // clear sharing item
  sharingItems.value = [];

  // if we are not in sharing mode, return directly
  if (!isSharingItem.value) {
    return;
  }

  // fetch data
  let uuid = sharingItemUuid.value!;
  let rv = await apiCollectionGetSharing(token.currentToken, uuid);
  if (typeof rv === 'undefined') {
    console.error(`fail to fetch sharing target for collection ${uuid}`);
    return;
  }

  // render then
  sharingItems.value = rv;
}

const addSharingItem = async () => {
  let uuid = sharingItemUuid.value!;
  let lastChange = ownedItems.value.get(uuid)![2];
  let new_username = pendingSharingItemUsername.value;
  if (new_username === '') {
    return;
  }

  // order adding
  let rv = await apiCollectionAddSharing(token.currentToken, uuid, new_username, lastChange);
  if (typeof rv === 'undefined') {
    messagebox.value?.show("An add operation failed. It may caused by wrong arguments. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // push new item in list
  sharingItems.value.push(new_username);
  // the return value is the new last change
  ownedItems.value.get(uuid)![2] = rv;
}

const deleteSharingItem = async (username: string) => {
  let uuid = sharingItemUuid.value!;
  let lastChange = ownedItems.value.get(uuid)![2];

  // order deleting
  let rv = await apiCollectionDeleteSharing(token.currentToken, uuid, username, lastChange);
  if (typeof rv === 'undefined') {
    messagebox.value?.show("A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
    return;
  }

  // remove this item
  sharingItems.value.splice(sharingItems.value.indexOf(username), 1);
  // the return value is the new last change
  ownedItems.value.get(uuid)![2] = rv;
}

</script>

<template>
  <div class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
    <h1 class="title">Owned</h1>
    <div class="control-list">
      <div class="field has-addons">
        <div class="control">
          <input v-model="pendingOwnedItemName" class="input" type="text">
        </div>
        <div class="control" @click="addOwnedItem">
          <a class="button is-primary">
            <span class="icon is-small"><font-awesome-icon icon="fas fa-plus"></font-awesome-icon></span>
          </a>
        </div>
      </div>
      <div class="control" @click="refreshOwnedItem">
        <a class="button is-primary">
          <span class="icon is-small"><font-awesome-icon icon="fas fa-sync"></font-awesome-icon></span>
        </a>
      </div>
    </div>

    <div v-for="item in ownedItems.values()" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
      <OwnedItem :uuid="item[0]" :name="item[1]" @delete="deleteOwnedItem" @share="shareOwnedItem"
        @update="updateOwnedItem" />
    </div>
  </div>

  <div v-show="isSharingItem" class="container" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
    <h1 class="title">Sharing target</h1>
    <label class="label">
      <span>Editing: </span>
      <span>{{ isSharingItem ? ownedItems.get(sharingItemUuid!)![1] : "" }}</span>
    </label>

    <div class="control-list">
      <div class="field has-addons">
        <div class="control">
          <input v-model="pendingSharingItemUsername" class="input" type="text">
        </div>
        <div class="control" @click="addSharingItem">
          <a class="button is-primary">
            <span class="icon is-small"><font-awesome-icon icon="fas fa-plus"></font-awesome-icon></span>
          </a>
        </div>
      </div>
      <div class="control" @click="refreshSharingItem">
        <a class="button is-primary">
          <span class="icon is-small"><font-awesome-icon icon="fas fa-sync"></font-awesome-icon></span>
        </a>
      </div>
    </div>

    <div v-for="item in sharingItems" style="display: flex; flex-flow: column; margin-top: 1.25rem;">
      <SharingItem :username="item" @delete="deleteSharingItem" />
    </div>
  </div>

  <MessageBox ref="messagebox" />
</template>

<style scoped></style>
