<template>
  <div class="timeline">
    <div class="timelime-control">
      <h1>Planning global de l'événement</h1>
      <div class="actions">
        <button
          class="btn small secondary"
          @click="createCreneau"
          :disabled="creneauGroupList.length == 0"
        >
          <i class="material-icons">create</i>Creneau
        </button>
        <button class="btn small secondary" @click="createRessource">
          <i class="material-icons">create</i>Ligne
        </button>
        <button class="btn icon small primary tooltiped" aria-tooltip="Zoomer" @click="zoom(1)">
          <i class="material-icons">zoom_in</i>
        </button>
        <button class="btn icon small primary tooltiped" aria-tooltip="Dezoomer" @click="zoom(-1)">
          <i class="material-icons">zoom_out</i>
        </button>
      </div>
    </div>
    <jc-timeline
      ref="timeline"
      :slotduration="slotduration"
      :legendspan="legendspan"
      :slotwidth="slotwidth"
      :start="start.toDate().toISOString()"
      :end="end.toDate().toISOString()"
      @event-change="eventChangeHandler"
      @item-selected="selectionChangeHandler"
      @reorder-ressource="ressourceChangeHandler"
    ></jc-timeline>
  </div>

  <editeur-creneau
    class="planning"
    v-if="currentCreneau"
    :creneau="currentCreneau"
    @create="createCreneau"
    @delete="deleteCreneau"
    @duplicate="duplicateCreneau"
    @edit="updateCreneau"
  ></editeur-creneau>
  <editeur-ligne
    class="planning"
    v-else
    :creneauGroupId="currentCreneauGroupId"
    @create="createRessource"
    @delete="deleteRessource"
    @edit="updateCreneauGroup"
  ></editeur-ligne>
</template>

<script lang="ts">
import { v4 as uuidv4 } from "uuid";
import { defineComponent } from "vue";
import Timeline from "jc-timeline/lib/Timeline";
import { Event as jcEvent } from "jc-timeline/lib/Event";
import EditeurCreneau from "@/components/EditeurCreneau.vue";
import EditeurLigne from "@/components/EditeurCreneauGroup.vue";
import { Ressource } from "jc-timeline";

import Creneau from "@/models/Creneau";
import { MutationTypes } from "@/store/Mutations";
import Selectable from "node_modules/jc-timeline/lib/utils/selectable";
import toast from "@/utils/Toast";

import * as dayjs from "dayjs";
import "dayjs/locale/fr";
dayjs.locale("fr");

type changePayload = {
  items: Array<jcEvent>;
};

export default defineComponent({
  name: "Planning",
  components: {
    EditeurCreneau,
    EditeurLigne,
  },
  data() {
    return {
      currentCreneau: undefined as Creneau | undefined,
      currentCreneauGroup: undefined as Ressource | undefined,
      zoomLevel: 14,
      slotduration: 30,
      legendspan: 2,
      slotwidth: 30,
    };
  },
  methods: {
    createCreneau(): void {
      // take the current crenau as reference if any
      const groupId = this.currentCreneau
        ? this.currentCreneau.ressourceId
        : // else the current row as reference if any
        this.currentCreneauGroup
        ? this.currentCreneauGroup.id
        : // else the first row as reference if any
        this.creneauList.length > 0
        ? this.creneauList[0].id
        : false;
      if (groupId) {
        const start = new Date(this.timeline.start);
        const e = this.timeline.addEvent(
          new jcEvent({
            id: uuidv4(),
            start: start,
            end: new Date(start.getTime() + 1000 * 60 * 60),
            ressourceId: groupId,
            title: "Nouveau creneau",
          })
        );
        if (e) {
          this.timeline.clearSelectedItems();
          e.selected = true;
          const creneau = new Creneau({
            event: e,
            penibility: 12,
            minAttendee: 1,
            maxAttendee: 1,
            benevoleIdList: [],
            competencesIdList: [],
            description: "",
            isMeal: false,
            fixedAttendee: false,
          });
          this.$store.commit(MutationTypes.addCreneau, creneau);

          this.currentCreneau = this.$store.getters.getCreneauById(creneau.id);
          this.currentCreneauGroup = undefined;
        }
      } else {
        toast({
          html:
            "Erreur: Pas de ligne auquel associer un nouveau creneau.<br>" +
            " Veuillez selectioné un créneau existant ou une ligne.",
        });
      }
    },
    createRessource(): void {
      const ressource = new Ressource({
        id: uuidv4(),
        title: "Nouvelle ligne",
      });
      this.$store.commit(MutationTypes.addCreneauGroupAt, { pos: 0, r: ressource });
      this.timeline.clearSelectedItems();
      this.timeline.addRessource(ressource).selected = true;
      this.currentCreneauGroup = ressource;
    },
    duplicateCreneau(payload: Creneau) {
      const newCreneau = new Creneau({
        ...payload.toJSON(),
        event: new jcEvent({ ...payload.event, id: uuidv4() }),
      });
      newCreneau.title = "Copy de " + newCreneau.title;
      this.timeline.addEvent(newCreneau.event);
      this.$store.commit(MutationTypes.addCreneau, newCreneau);
      this.currentCreneau = newCreneau;
    },
    deleteRessource(): void {
      if (this.currentCreneauGroup) {
        const contentRemoved = this.timeline.removeRessourceById(this.currentCreneauGroup.id);
        contentRemoved.ressources.map((r) =>
          this.$store.commit(MutationTypes.removeCreneauGroup, r)
        );
        contentRemoved.items.map((e) => {
          const crenenau = this.$store.getters.getCreneauById(e.id);
          if (crenenau) this.$store.commit(MutationTypes.removeCreneau, crenenau);
        });
      }
    },
    deleteCreneau(): void {
      if (this.currentCreneau) {
        this.timeline.removeEventById(this.currentCreneau.id);
        this.$store.commit(MutationTypes.removeCreneau, this.currentCreneau);
      }
    },
    selectionChangeHandler(ev: CustomEvent) {
      const elts = ev.detail.items as Array<Selectable>;
      if (elts.length == 1) {
        const item = elts[0];
        if (item instanceof Ressource) {
          this.currentCreneauGroup = item;
          this.currentCreneau = undefined;
        }
        if (item instanceof jcEvent) {
          this.currentCreneau = this.$store.getters.getCreneauById(item.id);
          this.currentCreneauGroup = undefined;
        }
      }
      if (elts.length == 0) {
        this.currentCreneau = undefined;
        this.currentCreneauGroup = undefined;
      }
    },
    eventChangeHandler(ev: CustomEvent<changePayload>) {
      this.currentCreneauGroup = undefined;
      const jcEvents = ev.detail.items;

      for (let index = 0; index < jcEvents.length; index++) {
        const element = jcEvents[index];
        this.$store.commit(MutationTypes.editCreneau, {
          id: element.id,
          field: "start",
          value: element.start,
        });
        this.$store.commit(MutationTypes.editCreneau, {
          id: element.id,
          field: "end",
          value: element.end,
        });
        this.$store.commit(MutationTypes.editCreneau, {
          id: element.id,
          field: "ressourceId",
          value: element.ressourceId,
        });
        this.currentCreneau = this.$store.getters.getCreneauById(element.id);
      }
    },
    ressourceChangeHandler(ev: CustomEvent<{ ressources: Array<Ressource> }>) {
      this.$store.commit(MutationTypes.reorderCreneauGroup, ev.detail.ressources);
    },
    updateCreneauGroup<K extends keyof Ressource>(payload: {
      id: string;
      field: K;
      value: Ressource[K];
    }) {
      const prevState = this.$store.getters.getCreneauGroupById(payload.id);
      if (prevState && prevState[payload.field] !== payload.value) {
        const r = this.timeline.updateRessource(payload.id, payload.field, payload.value);
        if (r) {
          payload.value = r[payload.field];
        }
        this.$store.commit(MutationTypes.editCreneauGroup, payload);
      }
    },
    updateCreneau<K extends keyof Creneau>(payload: { id: string; field: K; value: Creneau[K] }) {
      this.$store.commit(MutationTypes.editCreneau, payload);
      const creneau = this.$store.getters.getCreneauById(payload.id);
      if (creneau) {
        this.timeline.removeEventById(payload.id);
        this.timeline.addEvent(creneau.event);
      }
    },
    zoom(lvl: number) {
      const durations = [
        10080,
        10080,
        10080,
        10080,
        10080,
        1440,
        1440,
        720,
        720,
        360,
        120,
        60,
        60,
        60,
        30,
        30,
        15,
        5,
      ];
      const slotWidths = [40, 60, 80, 120, 160, 30, 40, 30, 50, 40, 25, 20, 30, 40, 30, 40, 35, 20];
      const legendSpans = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 4];
      this.zoomLevel += lvl;
      this.zoomLevel = Math.min(Math.max(0, this.zoomLevel), durations.length - 1);

      this.slotduration = durations[this.zoomLevel];
      this.slotwidth = slotWidths[this.zoomLevel];
      this.legendspan = legendSpans[this.zoomLevel];
    },
  },
  computed: {
    timeline(): Timeline {
      const output = this.$refs["timeline"];
      return output as Timeline;
    },
    currentCreneauGroupId(): string {
      return this.currentCreneauGroup ? this.currentCreneauGroup.id : "";
    },
    creneauList(): Array<Creneau> {
      return this.$store.state.creneauList;
    },
    eventList(): Array<jcEvent> {
      return this.creneauList.map((o) => o.event);
    },
    creneauGroupList(): Array<Ressource> {
      return this.$store.state.creneauGroupList;
    },
    start(): dayjs.Dayjs {
      return this.$store.state.evenement.startingDate;
    },
    end(): dayjs.Dayjs {
      return this.$store.state.evenement.endingDate;
    },
  },
  watch: {},
  mounted() {
    this.timeline.setAttribute("start", this.start.toISOString());
    this.timeline.setAttribute("end", this.end.toISOString());
    this.timeline.addRessources(this.creneauGroupList);
    this.timeline.addEvents(this.eventList);
    this.timeline.setLegendUnitFormat("d", "dddd D MMMM");
    this.timeline.customStyle = `.bubble{
    padding: 2px 4px;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    right: -5px;
    bottom: -5px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: bold;
    z-index:1;
    background: #08875b;
    transform: translateX(50%);
    white-space: nowrap;
}
.bubble.red{
    background: #e4002b;
}
.bubble.orange{
    background: #fbca32;
}`;
    this.timeline.clearSelectedItems();
  },
});
</script>

<style lang="scss" scoped>
.planning-container {
  display: flex;
  justify-content: center;
}
.timeline {
  margin: 0px 16px;
  width: 100%;
}
jc-timeline {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 13rem);
}
.actions {
  display: inline-flex;
  justify-content: left;
  margin-bottom: 12px;
}
.actions > .btn {
  margin-right: 4px;
}
</style>
