<template>
  <div id="slot-container">
    <v-card class="sidebar">
      <v-navigation-drawer floating permanent>
        <v-list dense rounded>
          <time-grid-field
            solo
            rounded
            hide-details
            v-model="internalTimeGrid"
          />
          <slot-creator
            :query="$apollo.queries.items"
            :time-grid="internalTimeGrid.id"
            v-if="internalTimeGrid"
            :breaks="createBreaks"
          >
            <template #activator="{ on, attrs }">
              <v-list-item
                link
                v-bind="attrs"
                v-on="on"
                @click="createBreaks = false"
              >
                <v-list-item-icon>
                  <v-icon>$plus</v-icon>
                </v-list-item-icon>
                <v-list-item-content>
                  <v-list-item-title>{{
                    $t("lesrooster.slot.create_items")
                  }}</v-list-item-title>
                </v-list-item-content>
              </v-list-item>
              <v-list-item
                link
                v-bind="attrs"
                v-on="on"
                @click="createBreaks = true"
              >
                <v-list-item-icon>
                  <v-icon>$plus</v-icon>
                </v-list-item-icon>
                <v-list-item-content>
                  <v-list-item-title>{{
                    $t("lesrooster.break.create_items")
                  }}</v-list-item-title>
                </v-list-item-content>
              </v-list-item>
            </template>
          </slot-creator>

          <copy-from-time-grid-menu
            v-if="internalTimeGrid"
            :deny-ids="[internalTimeGrid.id]"
            @confirm="copyFromGrid"
          >
            <template #activator="{ on, attrs }">
              <v-list-item link v-bind="attrs" v-on="on">
                <v-list-item-icon>
                  <v-icon>mdi-content-copy</v-icon>
                </v-list-item-icon>
                <v-list-item-content>
                  <v-list-item-title>
                    {{ $t("lesrooster.actions.copy_last_configuration") }}
                  </v-list-item-title>
                </v-list-item-content>
              </v-list-item>
            </template>
          </copy-from-time-grid-menu>
        </v-list>
      </v-navigation-drawer>
    </v-card>

    <v-hover
      v-for="weekday in weekdays"
      :key="'weekday-' + weekday"
      :style="{
        gridColumn: weekday,
      }"
      v-slot="{ hover }"
    >
      <v-card :loading="$apollo.queries.items.loading || loading.main">
        <v-card-title
          class="d-flex flex-wrap justify-space-between align-center fill-height"
        >
          <span class="min-height">{{ $t("weekdays." + weekday) }}</span>

          <v-tooltip bottom>
            <template #activator="{ on, attrs }">
              <v-btn
                @click="deleteSlotsOfDay(weekday)"
                icon
                v-bind="attrs"
                v-on="on"
                v-show="hover"
              >
                <v-icon>$deleteContent</v-icon>
              </v-btn>
            </template>
            <span v-t="'actions.delete'"></span>
          </v-tooltip>

          <v-menu offset-y>
            <template #activator="{ on: menu, attrs }">
              <v-tooltip bottom>
                <template #activator="{ on: tooltip }">
                  <v-btn
                    icon
                    v-bind="attrs"
                    v-on="{ ...tooltip, ...menu }"
                    :loading="loading[weekday] || loading.main"
                    v-show="hover"
                  >
                    <v-icon>mdi-application-export</v-icon>
                  </v-btn>
                </template>
                <span v-t="'lesrooster.actions.copy_to_day'"></span>
              </v-tooltip>
            </template>
            <v-list>
              <v-list-item
                v-for="(item, index) in weekdays.filter(
                  (day) => day !== weekday,
                )"
                :key="index"
                link
              >
                <v-list-item-title @click="copyTo(weekday, item)">{{
                  $t("weekdays." + item)
                }}</v-list-item-title>
              </v-list-item>
            </v-list>
          </v-menu>

          <v-btn
            v-if="canAddDay(left(weekday))"
            v-show="hover"
            color="secondary"
            fab
            dark
            small
            absolute
            left
            style="left: calc(-20px - 0.5rem)"
            @click="add(left(weekday))"
          >
            <v-icon>mdi-table-column-plus-before</v-icon>
          </v-btn>
          <v-btn
            v-if="canAddDay(right(weekday))"
            v-show="hover"
            color="secondary"
            fab
            dark
            small
            absolute
            right
            style="right: calc(-20px - 0.5rem)"
            @click="add(right(weekday))"
          >
            <v-icon>mdi-table-column-plus-after</v-icon>
          </v-btn>
        </v-card-title>
      </v-card>
    </v-hover>

    <slot-card
      v-for="slot in slots"
      :key="'slot-' + slot.id"
      :item="slot"
      :disabled="
        $apollo.queries.items.loading || loading.main || loading[slot.weekday]
      "
      @click:delete="deleteSlot"
      @click:copy="copySingularSlotTodDay($event.item, $event.weekday)"
      :weekdays="weekdays"
      :id="'#slot-' + slot.id"
    />

    <delete-dialog
      :gql-delete-mutation="deleteMutation"
      :affected-query="$apollo.queries.items"
      :items="itemsToDelete"
      v-model="deleteDialog"
    >
      <template #title>
        {{
          $t("lesrooster.slot.confirm_delete_slots", {
            day: $t("weekdays." + weekdayToDelete),
          })
        }}
      </template>

      <template #body>
        <ul class="text-body-1">
          <li v-for="item in itemsToDelete" :key="'delete-' + item.id">
            {{ $t("lesrooster." + item.model.toLowerCase() + ".repr", item) }}
          </li>
        </ul>
      </template>
    </delete-dialog>
  </div>
</template>

<script>
import {
  carryOverSlots,
  copySlotsFromGrid,
  slots,
  deleteSlots,
} from "../breaks_and_slots/slot.graphql";
import DeleteDialog from "aleksis.core/components/generic/dialogs/DeleteDialog.vue";
import CopyFromTimeGridMenu from "../validity_range/CopyFromTimeGridMenu.vue";
import SlotCard from "./SlotCard.vue";
import SlotCreator from "./SlotCreator.vue";
import TimeGridField from "../validity_range/TimeGridField.vue";

export default {
  name: "LessonRaster",
  components: {
    TimeGridField,
    CopyFromTimeGridMenu,
    SlotCreator,
    DeleteDialog,
    SlotCard,
  },
  apollo: {
    items: {
      query: slots,
      variables() {
        return {
          filters: JSON.stringify({
            time_grid: this.internalTimeGrid.id,
          }),
        };
      },
      result(data) {
        console.log(data);
        this.weekdays = Array.from(
          new Set(data.data.items.map((slot) => slot.weekday)),
        ).sort();
      },
      skip() {
        return this.internalTimeGrid === null;
      },
    },
  },
  data() {
    return {
      weekdays: [],
      internalTimeGrid: null,
      loading: {
        main: false,
      },
      gqlQuery: slots,
      deleteMutation: deleteSlots,
      deleteDialog: false,
      itemsToDelete: [],
      weekdayToDelete: "",
      createBreaks: false,
    };
  },
  computed: {
    slots() {
      return (
        [...(this.items || [])].sort(
          (a, b) =>
            parseInt(a.timeStart.replace(":", "")) -
            parseInt(b.timeStart.replace(":", "")),
        ) || []
      );
    },
    columns() {
      return (
        "[side] 256px " + this.weekdays.map((day) => `[${day}] 1fr`).join(" ")
      );
    },
  },
  methods: {
    intDay(weekday) {
      return Number.isInteger(weekday) ? weekday : parseInt(weekday[2]);
    },
    canAddDay(weekday) {
      if (!weekday) {
        return false;
      }

      return !this.weekdays.includes(weekday);
    },
    add(weekday) {
      if (!this.weekdays.includes(weekday)) {
        this.weekdays.push(weekday);
        this.weekdays.sort();
      }
    },
    right(weekday) {
      return weekday === "A_6"
        ? null
        : weekday.replace(/\d+$/, (match) => parseInt(match) + 1);
    },
    left(weekday) {
      return weekday === "A_0"
        ? null
        : weekday.replace(/\d+$/, (match) => parseInt(match) - 1);
    },
    async copyTo(src, dest) {
      this.loading[dest] = true;

      // As there is an error when deleting breaks and normal slots in one action, we delete them separately
      // FIXME NO ACtion

      let that = this;

      await this.$apollo.mutate({
        mutation: carryOverSlots,
        variables: {
          timeGrid: this.internalTimeGrid.id,
          fromDay: this.intDay(src),
          toDay: this.intDay(dest),
        },
        update(
          store,
          {
            data: {
              carryOverSlots: { result },
            },
          },
        ) {
          let query = {
            ...that.$apollo.queries.items.options,
            variables: JSON.parse(
              that.$apollo.queries.items.previousVariablesJson,
            ),
          };
          // Read the data from cache for query
          const storedData = store.readQuery(query);

          if (!storedData) {
            // There are no data in the cache yet
            return;
          }

          storedData.items = [
            ...storedData.items.filter((item) => item.weekday !== dest),
            ...result,
          ];

          // Write data back to the cache
          store.writeQuery({ ...query, data: storedData });
        },
      });

      this.weekdays = this.weekdays.sort((a, b) => a[2] - b[2]);
      this.loading[dest] = false;
    },
    async copySingularSlotTodDay(slot, day) {
      const that = this;

      this.loading[day] = true;
      this.$apollo
        .mutate({
          mutation: carryOverSlots,
          variables: {
            timeGrid: this.internalTimeGrid.id || slot.timeGrid.id,
            fromDay: this.intDay(slot.weekday),
            toDay: this.intDay(day),
            only: [slot.id],
          },
          update(
            store,
            {
              data: {
                carryOverSlots: { result },
              },
            },
          ) {
            let query = {
              ...that.$apollo.queries.items.options,
              variables: JSON.parse(
                that.$apollo.queries.items.previousVariablesJson,
              ),
            };
            // Read the data from cache for query
            const storedData = store.readQuery(query);

            if (!storedData) {
              // There are no data in the cache yet
              return;
            }

            storedData.items.push(result[0]);

            // Write data back to the cache
            store.writeQuery({ ...query, data: storedData });
          },
        })
        .then(() => {
          this.$toastSuccess();
        })
        .catch(() => {
          this.$toastError();
        })
        .finally(() => {
          this.loading[day] = false;
        });
    },
    deleteSlot(slot) {
      this.itemsToDelete = [slot];
      this.deleteDialog = true;
    },
    deleteSlotsOfDay(weekday) {
      this.itemsToDelete = this.items.filter(
        (slot) => slot.weekday === weekday,
      );
      this.weekdayToDelete = weekday;
      this.deleteDialog = true;
    },
    copyFromGrid(existingTimeGrid) {
      if (!this.internalTimeGrid || !this.internalTimeGrid.id) return;

      let that = this;
      this.loading.main = true;

      this.$apollo
        .mutate({
          mutation: copySlotsFromGrid,
          variables: {
            fromTimeGrid: existingTimeGrid.id,
            toTimeGrid: this.internalTimeGrid.id,
          },
          update(
            store,
            {
              data: {
                copySlotsFromGrid: { result, deleted },
              },
            },
          ) {
            let query = {
              ...that.$apollo.queries.items.options,
              variables: JSON.parse(
                that.$apollo.queries.items.previousVariablesJson,
              ),
            };
            // Read the data from cache for query
            const storedData = store.readQuery(query);

            if (!storedData) {
              // There are no data in the cache yet
              return;
            }

            for (const id of deleted) {
              // Remove item from stored data
              const index = storedData.items.findIndex((m) => m.id === id);
              storedData.items.splice(index, 1);
            }

            storedData.items.push(...result);

            // Write data back to the cache
            store.writeQuery({ ...query, data: storedData });
          },
        })
        .then(() => {
          this.$toastSuccess();
        })
        .catch(() => {
          this.$toastError();
        })
        .finally(() => {
          this.loading.main = false;
        });
    },
  },
};
</script>

<style scoped>
#slot-container {
  display: grid;
  grid-template-columns: v-bind(columns);
  grid-auto-rows: 1fr;
  gap: 0.7rem;
  overflow-x: scroll;
  margin: -1em;
  padding: 1em;
  grid-auto-flow: column;
}

.min-height {
  min-height: 36px;
}

.sidebar {
  position: fixed;
  z-index: 1;
}
</style>