<template>
  <q-card bordered>
    <div class="text-weight-medium q-px-xs">
      {{ asHour(modelValue.start) }}
      <template v-if="modelValue.end">- {{ asHour(modelValue.end) }}</template>
    </div>
    <div class="q-px-xs">
      {{ typeName }}
    </div>
    <div class="col-auto q-px-xs" style="font-size: 10px">
      {{ modelValue.comment }}
    </div>
    <div>
      <q-select
        :model-value="modelValue.services"
        :disable="!canAssignOther || modelValue.locked"
        :options="options"
        option-value="userid"
        filled
        multiple
        use-input
        label="Dienste"
        behavior="dialog"
        class="col-auto q-px-xs"
        @filter="filterUsers"
        @add="({ value }) => assign(value)"
        @remove="({ value }) => unassign(value)"
      >
        <template #selected-item="{ opt, toggleOption }">
          <service-user-chip :model-value="opt" removeable @remove="toggleOption" />
        </template>
        <template #option="{ opt, itemProps }">
          <q-item v-bind="itemProps">
            <q-item-section avatar>
              <user-avatar :model-value="opt.userid" />
            </q-item-section>
            <q-item-section>{{ userDisplay(opt.userid) }}</q-item-section>
            <q-item-section style="max-width: 10em" side>
              <q-input
                v-model.number="opt.value"
                type="number"
                min="0"
                step="0.25"
                dense
                filled
                @click.stop=""
              />
            </q-item-section>
            <q-item-section side>
              <q-toggle v-model="opt.is_backup" label="Backup" left-label />
            </q-item-section>
          </q-item>
        </template>
      </q-select>
      <div class="row col-12 justify-end">
        <q-btn
          v-if="!modelValue.locked && !isEnrolled && !isFull && canAssign"
          flat
          color="primary"
          label="Eintragen"
          @click="assign()"
        />
        <q-btn v-if="isEnrolled && !modelValue.locked" flat color="secondary" label="Optionen">
          <q-menu auto-close>
            <q-list style="min-width: 100px">
              <q-item v-if="!isFull && canInvite" clickable @click="invite">
                <q-item-section>Einladen</q-item-section>
              </q-item>
              <q-item clickable @click="transfer">
                <q-item-section>Tauschen</q-item-section>
              </q-item>
              <q-item v-if="isBackup" clickable @click="backup(false)">
                <q-tooltip>Backup zu vollem Dienst machen</q-tooltip>
                <q-item-section>Dienst</q-item-section>
                <q-item-section side><q-icon name="mdi-eye" /></q-item-section>
              </q-item>
              <q-item v-else clickable @click="backup(true)">
                <q-tooltip>Nur als Backup eintragen</q-tooltip>
                <q-item-section>Backup</q-item-section>
                <q-item-section side><q-icon name="mdi-eye-off" /></q-item-section>
              </q-item>
              <q-separator />
              <q-item clickable @click="unassign()">
                <q-item-section class="text-negative">Austragen</q-item-section>
              </q-item>
            </q-list>
          </q-menu>
        </q-btn>
      </div>
    </div>
  </q-card>
</template>

<script lang="ts">
import { date, useQuasar } from 'quasar';
import { defineComponent, onBeforeMount, computed, ref, PropType } from 'vue';
import { asHour, hasPermission, useMainStore, useUserStore } from '@flaschengeist/api';
import { useEventStore } from '../../../store';
import { PERMISSIONS } from '../../../permissions';

import TransferInviteDialog from './TransferInviteDialog.vue';
import ServiceUserChip from './ServiceUserChip.vue';
import { UserAvatar } from '@flaschengeist/api/components';

export default defineComponent({
  name: 'JobSlot',
  components: { ServiceUserChip, UserAvatar },
  props: {
    modelValue: {
      required: true,
      type: Object as PropType<FG.Job>,
    },
    eventId: {
      required: true,
      type: Number,
    },
  },
  emits: { 'update:modelValue': (v: FG.Job) => !!v },
  setup(props, { emit }) {
    const store = useEventStore();
    const mainStore = useMainStore();
    const userStore = useUserStore();
    const quasar = useQuasar();

    // Make sure users are loaded if we can assign them
    onBeforeMount(() => void userStore.getUsers());

    /* Stuff used for general display */
    // Get displayname of user
    function userDisplay(id: string) {
      return userStore.findUser(id)?.display_name || id;
    }

    // The name of the current job
    const typeName = computed(() =>
      typeof props.modelValue.type === 'object'
        ? props.modelValue.type.name
        : store.jobTypes.find((j) => j.id === props.modelValue.type)?.name ||
          'Unbekannter Diensttyp'
    );

    // The service of the current user if self assigned to the job
    const service = computed(() =>
      props.modelValue.services.find((service) => service.userid == mainStore.currentUser.userid)
    );

    // Weather the current user is assigned to the job
    const isEnrolled = computed(() => service.value !== undefined);

    // If the job has enough assigned services
    const isFull = computed(
      () =>
        props.modelValue.services.map((s) => s.value).reduce((p, c) => p + c, 0) >=
        props.modelValue.required_services
    );

    // If current user is only backup service
    const isBackup = computed(() => service.value?.is_backup || false);

    // If it is still possible to invite other users (= job is today or in the future)
    const canInvite = computed(
      () =>
        (props.modelValue.end || props.modelValue.start) >
        date.subtractFromDate(
          date.buildDate({ hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }),
          { days: 1 }
        )
    );

    // Assign user to a job
    async function assign(service?: FG.Service) {
      service = service || {
        userid: mainStore.currentUser.userid,
        is_backup: false,
        value: 1,
      };
      try {
        const job = await store.assignToJob(props.modelValue.id, service);
        emit('update:modelValue', job);
      } catch (error) {
        console.warn(error);
        quasar.notify({
          group: false,
          type: 'negative',
          message: 'Fehler beim Ein- oder Austragen als Dienst',
          timeout: 10000,
          progress: true,
          actions: [{ icon: 'mdi-close', color: 'white' }],
        });
      }
    }

    // open invite dialog (or transfer)
    function invite(isInvite = true) {
      quasar.dialog({
        component: TransferInviteDialog,
        componentProps: {
          isInvite: isInvite,
          job: props.modelValue,
        },
      });
    }

    /* Stuff needed if we can assign other user */
    // Current user can assign other users
    const canAssignOther = computed(() => hasPermission(PERMISSIONS.ASSIGN_OTHER));

    const canAssign = computed(() => hasPermission(PERMISSIONS.ASSIGN));

    // options shown in the select
    const options = ref([] as FG.Service[]);

    // users which are available (e.g. not already assigned)
    const freeUsers = computed(() =>
      userStore.users.filter((u) => props.modelValue.services.every((s) => s.userid !== u.userid))
    );

    // used to filter options based on user input
    function filterUsers(
      input: string,
      doneFn: (
        callbackFn: () => void,
        afterFn?: (ref: { [index: string]: unknown }) => void
      ) => void,
      abortFn: () => void
    ) {
      if (freeUsers.value.length == 0) return abortFn();

      // Filter the options
      doneFn(() => {
        // Skip filter options if input is too short
        if (!input || input.length < 2) {
          options.value = freeUsers.value.map<FG.Service>((u) => ({
            userid: u.userid,
            value: 1,
            is_backup: false,
          }));
          return;
        }
        // Search matching string within all names
        options.value = freeUsers.value
          .filter((u) =>
            input
              .toLowerCase()
              .split(' ')
              .every(
                (needle) =>
                  u.display_name.toLowerCase().indexOf(needle) > -1 ||
                  u.firstname.toLowerCase().indexOf(needle) > -1 ||
                  u.lastname.toLowerCase().indexOf(needle) > -1
              )
          )
          .map<FG.Service>((u) => ({ userid: u.userid, value: 1, is_backup: false }));
      });
    }

    return {
      assign,
      unassign: (s?: FG.Service) => assign(Object.assign({}, s || service.value, { value: -1 })),
      backup: (is_backup: boolean) => assign(Object.assign({}, service.value, { is_backup })),
      canAssignOther,
      canAssign,
      canInvite,
      filterUsers,
      isBackup,
      isEnrolled,
      isFull,
      invite: () => invite(true),
      transfer: () => invite(false),
      typeName,
      userDisplay,
      options,
      asHour,
    };
  },
});
</script>

<style scoped></style>
