<template>
  <q-page padding>
    <q-table
      v-model:pagination="pagination"
      title="Dienstanfragen"
      :rows="rows"
      :columns="columns"
      row-key="id"
      :loading="loading"
      binary-state-sort
      @request="onRequest"
    >
      <template #top-right>
        <q-toggle v-model="showSent" dense label="Gesendete anzeigen" />
      </template>
      <template #body-cell-inviter="props">
        <q-td :props="props">
          <div>
            {{ props.value.with
            }}<q-icon v-if="props.value.sender" name="mdi-account-alert">
              <q-tooltip>Gesendet von {{ props.value.sender }}</q-tooltip>
            </q-icon>
          </div>
        </q-td>
      </template>
      <template #body-cell-type="props">
        <q-td :props="props">
          <q-icon size="sm" :name="types[props.value].icon">
            <q-tooltip>{{ types[props.value].tooltip }}</q-tooltip>
          </q-icon>
        </q-td>
      </template>
      <template #body-cell-actions="props">
        <q-td :props="props">
          <!-- <q-btn v-for="action in props.value" :key="action.icon" :icon="action.icon" dense /> -->
          <div class="row justify-end">
            <div v-for="action in props.value" :key="action.icon">
              <q-btn
                class="q-mx-xs"
                :icon="action.icon"
                dense
                @click="action.onClick"
                round
                :color="action.color"
              >
                <q-tooltip>{{ action.tooltip }}</q-tooltip>
              </q-btn>
            </div>
          </div>
        </q-td>
      </template>
    </q-table>
  </q-page>
</template>

<script lang="ts">
import { formatStartEnd, useMainStore, useUserStore } from '@flaschengeist/api';
import { computed, defineComponent, ref, onBeforeMount, watch } from 'vue';
import { QTableProps } from 'quasar';
import { Job } from '../store/models';
import { useEventStore } from '../store';
import { EventNotification, InvitationData, InvitationResponseData } from '../events';

export default defineComponent({
  name: 'PageEventRequests',
  setup() {
    const store = useEventStore();
    const userStore = useUserStore();
    const mainStore = useMainStore();

    interface RowData extends FG.Invitation {
      inviter: FG.User;
      invitee: FG.User;
      transferee?: FG.User;
      job: Job;
    }

    // Generated data used for the table
    const rows = ref([] as RowData[]);
    // Loading state for data generation (getting Job information)
    const loading = ref(false);
    // Which "page" of invitations to show (we load all, but do not fetch all jobs)
    const pagination = ref({
      sortBy: 'desc',
      descending: false,
      page: 1,
      rowsPerPage: 3,
      rowsNumber: 4,
    });
    // Real invitations
    const invitations = computed(() =>
      showSent.value
        ? store.invitations
        : store.invitations.filter((i) => i.inviter_id !== mainStore.currentUser.userid)
    );
    const all_notifications = computed<EventNotification[]>(() => {
      return mainStore.notifications.filter((n) => n.plugin === 'events') as EventNotification[];
    });
    const showSent = ref(false);

    async function fillRows(data: FG.Invitation[]) {
      const res = [] as RowData[];
      for (let i = 0; i < data.length; ++i) {
        res.push(
          Object.assign({}, data[i], {
            inviter: <FG.User>await userStore.getUser(data[i].inviter_id),
            invitee: <FG.User>await userStore.getUser(data[i].invitee_id),
            transferee: data[i].transferee_id
              ? await userStore.getUser(<string>data[i].transferee_id)
              : undefined,
            job: new Job(await store.getJob(data[i].job_id)),
          })
        );
      }
      rows.value = res;
    }
    type onRequestType = QTableProps['onRequest'];

    const onRequest: onRequestType = (requestProp) => {
      const { page, rowsPerPage, sortBy, descending } = requestProp.pagination;
      loading.value = true;

      // Number of total invitations
      pagination.value.rowsNumber = invitations.value.length;
      // calculate starting row of data
      const startRow = (page - 1) * rowsPerPage;
      // get all rows if "All" (0) is selected
      const fetchCount =
        rowsPerPage === 0
          ? pagination.value.rowsNumber
          : Math.min(pagination.value.rowsNumber - startRow, rowsPerPage);
      // copy array, as sort is in-place
      function sorting<T = any>(key: string | keyof T, descending = true) {
        return (a: T, b: T) => {
          const v1 = a[key as keyof T];
          if (v1 === undefined) return descending ? -1 : 1;
          const v2 = b[key as keyof T];
          if (v2 === undefined) return descending ? 1 : -1;
          return (v1 < v2 ? -1 : 1) * (descending ? -1 : 1);
        };
      }

      // Set table data
      fillRows(
        [...invitations.value]
          .sort(sorting(sortBy, descending))
          .slice(startRow, startRow + fetchCount)
      )
        .then(() => {
          pagination.value.page = page;
          pagination.value.rowsPerPage = rowsPerPage;
          pagination.value.sortBy = sortBy;
          pagination.value.descending = descending;
        })
        .finally(() => (loading.value = false));
    };

    onBeforeMount(() => {
      void Promise.allSettled([
        userStore.getUsers(),
        store.getInvitations(),
        store.getJobTypes(),
      ]).then(() =>
        onRequest({ pagination: pagination.value, filter: () => [], getCellValue: () => [] })
      );
    });

    watch(showSent, () => {
      onRequest({ pagination: pagination.value, filter: () => [], getCellValue: () => [] });
    });

    function getType(row: RowData) {
      var idx = row.transferee === undefined ? 0 : 1;
      if (row.inviter.userid === mainStore.currentUser.userid) idx += 2;
      return idx;
    }

    const dimmed = (row: RowData) => (getType(row) >= types.length / 2 ? 'dimmed' : undefined);
    const columns = [
      {
        label: 'Type',
        name: 'type',
        align: 'left',
        field: getType,
        sortable: true,
        classes: dimmed,
      },
      {
        label: 'Dienstart',
        align: 'left',
        name: 'job_type',
        sortable: true,
        classes: dimmed,
        field: (row: RowData) =>
          store.jobTypes.find((t) => t.id == row.job.type)?.name || 'Unbekannt',
      },
      {
        label: 'Wann',
        align: 'center',
        sortable: true,
        name: 'job_start',
        classes: dimmed,
        field: (row: RowData) => formatStartEnd(row.job.start, row.job.end) + ' Uhr',
      },
      {
        label: 'Von / Mit',
        name: 'inviter',
        align: 'center',
        classes: dimmed,
        field: (row: RowData) => {
          const sender =
            row.transferee_id && row.transferee_id !== row.inviter_id
              ? row.inviter.display_name
              : undefined;

          if (row.invitee_id === mainStore.currentUser.userid) {
            return {
              with: row.transferee ? row.transferee.display_name : row.inviter.display_name,
              sender,
            };
          }
          if (row.transferee_id === mainStore.currentUser.userid) {
            return {
              with: row.invitee.display_name,
              sender,
            };
          }
          return {
            with: !row.transferee
              ? row.invitee.display_name
              : `${row.transferee.display_name} <-> ${row.invitee.display_name}`,
          };
        },
      },
      {
        label: 'Aktionen',
        align: 'right',
        name: 'actions',
        classes: dimmed,
        field: (row: RowData) => {
          const sender = row.inviter_id === mainStore.currentUser.userid;
          let actions = [];
          const reject = {
            icon: 'mdi-delete',
            tooltip: 'Einladung löschen',
            color: 'negative',
            onClick: () => {
              void store.rejectInvitation(row.id);
              onRequest({
                pagination: pagination.value,
                filter: () => [],
                getCellValue: () => [],
              });
              const notification = all_notifications.value.find(
                (n) => (<InvitationData>n.data).invitation === row.id
              );
              if (notification !== undefined) {
                void mainStore.removeNotification(notification.id);
              }
            },
          };
          const accept = {
            icon: 'mdi-check',
            tooltip: 'Einladung annehmen',
            color: 'primary',
            onClick: () => {
              void store.acceptInvitation(row.id);
              onRequest({
                pagination: pagination.value,
                filter: () => [],
                getCellValue: () => [],
              });
              const notification = all_notifications.value.find(
                (n) => (<InvitationData>n.data).invitation === row.id
              );
              if (notification !== undefined) {
                void mainStore.removeNotification(notification.id);
              }
            },
          };
          if (sender) {
            actions.push(reject);
          } else if (row.invitee_id === mainStore.currentUser.userid) {
            actions.push(accept);
            actions.push({ ...reject, icon: 'mdi-close' });
          }
          return actions;
        },
      },
    ];

    const types = [
      { icon: 'mdi-calendar', tooltip: 'Einladung' },
      { icon: 'mdi-calendar-sync', tooltip: 'Tauschanfrage' },
      { icon: 'mdi-calendar-outline', tooltip: 'Einladung (von dir)' },
      { icon: 'mdi-calendar-sync-outline', tooltip: 'Tauschanfrage (von dir)' },
    ];

    return {
      columns,
      loading,
      onRequest,
      pagination,
      rows,
      showSent,
      types,
    };
  },
});
</script>