<template>

   <div id="visgraph"></div>

   <teleport to="#visgraph-legend">
      <div class="post-menu">
         <div class="list-group mt-4">
            <button type="button" class="list-group-item list-group-item-action btn btn-create" @click="createRelationship">
               {{ $t('visgraph.add_link') }}
            </button>
            <a type="button" class="list-group-item list-group-item-action btn btn-misc" id="exportCanvasBtn" @click="exportCanvasAsImage">
               <i class="fa fa-camera fa-fw"></i> {{ $t('visgraph.screenshot') }}
            </a>
            <button type="button" class="list-group-item list-group-item-action btn btn-light" @click="refreshNetwork">
               <i class="fa fa-refresh fa-fw"></i> {{ $t('visgraph.refresh') }}
            </button>
         </div>

         <div v-if="displayHelpMessage" class="alert alert-info mt-3">
            {{ $t('visgraph.create_link_help') }}
         </div>

         <div class="my-4 legend">
            <h3>{{ $t('visgraph.Legend') }}</h3>
            <div class="list-group">
               <label class="list-group-item" v-for="(layer, i) in legendLayers" :key="`layer-${i}`">
                  <input
                     class="form-check-input me-1"
                     type="checkbox"
                     :value="layer.id"
                     v-model="checkedLayers"
                     @change="toggleLayer"
                     />
                     {{ layer.label }}
               </label>
            </div>
         </div>
      </div>
   </teleport>

   <teleport to="body">
      <modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
         <template v-slot:header>
            <h2 class="modal-title">{{ $t(modal.title) }}</h2>
            <!-- {{ modal.data.id }} -->
         </template>
         <template v-slot:body>
            <div v-if="modal.action === 'delete'">
               <p>{{ $t('visgraph.delete_confirmation_text') }}</p>
            </div>
            <div v-else>
               <form>
                  <div class="row">
                     <div class="col-12 text-center">{{ $t('visgraph.between') }}<br>{{ $t('visgraph.and') }}</div>
                     <div class="col">
                        <small>{{ getPersonAge(modal.data.from) }}</small>
                        <h4>{{ getPerson(modal.data.from).text }}</h4>
                        <p class="text-start" v-if="relation && relation.title">
                           <span v-if="reverse">
                              {{ $t('visgraph.relation_from_to_like', [ getPerson(modal.data.from).text, getPerson(modal.data.to).text, relation.reverseTitle.fr.toLowerCase() ])}}
                           </span>
                           <span v-else>
                              {{ $t('visgraph.relation_from_to_like', [ getPerson(modal.data.from).text, getPerson(modal.data.to).text, relation.title.fr.toLowerCase() ])}}
                           </span>
                        </p>
                     </div>
                     <div class="col text-end">
                        <small>{{ getPersonAge(modal.data.to) }}</small>
                        <h4>{{ getPerson(modal.data.to).text }}</h4>
                        <p class="text-end" v-if="relation && relation.title">
                           <span v-if="reverse">
                              {{ $t('visgraph.relation_from_to_like', [ getPerson(modal.data.to).text, getPerson(modal.data.from).text, relation.title.fr.toLowerCase() ])}}
                           </span>
                           <span v-else>
                              {{ $t('visgraph.relation_from_to_like', [ getPerson(modal.data.to).text, getPerson(modal.data.from).text, relation.reverseTitle.fr.toLowerCase() ])}}
                           </span>
                        </p>
                     </div>
                  </div>
                  <div class="my-3">
                     <VueMultiselect
                        id="relation"
                        label="title"
                        track-by="id"
                        :custom-label="customLabel"
                        :placeholder="$t('visgraph.choose_relation')"
                        :close-on-select="true"
                        :multiple="false"
                        :searchable="true"
                        :options="relations"
                        v-model="relation"
                        :value="relation"
                        >
                     </VueMultiselect>
                  </div>
                  <div class="form-check form-switch">
                     <input
                        class="form-check-input"
                        type="checkbox"
                        id="reverse"
                        v-model="reverse"
                        >
                     <label class="form-check-label" for="reverse">{{ $t('visgraph.reverse_relation') }}</label>
                  </div>
               </form>
            </div>
         </template>
         <template v-slot:footer>
            <button class="btn" :class="modal.button.class" @click="submitRelationship">
               {{ $t(modal.button.text)}}
            </button>
            <button class="btn btn-delete" v-if="modal.action === 'edit'" @click="dropRelationship"></button>
         </template>
      </modal>
   </teleport>

</template>

<script>
import vis from 'vis-network/dist/vis-network'
import { mapState, mapGetters } from "vuex"
import Modal from 'ChillMainAssets/vuejs/_components/Modal'
import VueMultiselect from 'vue-multiselect'
import { getRelationsList, postRelationship, patchRelationship, deleteRelationship } from "./api"
import { splitId, getAge } from "./vis-network"
import { visMessages } from "./i18n";

export default {
   name: "App",
   components: {
      Modal,
      VueMultiselect
   },
   props: ['household_id'],
   data() {
      return {
         container: '',
         checkedLayers: [],
         relations: [],
         displayHelpMessage: false,
         listenPersonFlag: 'normal',
         newEdgeData: {},
         modal: {
            showModal: false,
            modalDialogClass: "modal-md",
            title: null,
            action: null,
            data: {
               type: 'relationship',
               from: null,
               to: null,
               relation: null,
               reverse: false
            },
            button: {
               class: null,
               text: null
            },
         },
         canvas: null,
         link: null,
      }
   },
   computed: {
      ...mapGetters(['nodes', 'edges',
         // not used 'isInWhitelist', 'isHouseholdLoading', 'isCourseLoaded', 'isRelationshipLoaded', 'isPersonLoaded', 'isExcludedNode', 'countLinksByNode', 'getParticipationsByCourse', 'getMembersByHousehold', 'getPersonsGroup',
      ]),
      ...mapState(['persons', 'households', 'courses', 'excludedNodesIds', 'updateHack',
         // not used 'links', 'relationships', 'whitelistIds', 'personLoadedIds', 'householdLoadingIds', 'courseLoadedIds', 'relationshipLoadedIds',
      ]),

      visgraph_data() {
         //console.log('::: visgraph_data :::', this.nodes.length, 'nodes,', this.edges.length, 'edges')
         return {
            nodes: this.nodes,
            edges: this.edges
         }
      },

      refreshNetwork() {
         //console.log('--- refresh network')
         window.network.setData(this.visgraph_data)
      },

      legendLayers() {
         //console.log('--- refresh legend and rebuild checked Layers')
         this.checkedLayers = []
         let layersDisplayed = [
            ...this.nodes.filter(n => n.id.startsWith('household')),
            ...this.nodes.filter(n => n.id.startsWith('accompanying'))
         ]
         layersDisplayed.forEach(layer => {
            this.checkedLayers.push(layer.id)
         })
         return [
            ...this.households,
            ...this.courses
         ]
      },

      checkedLayers() { // required to refresh data checkedLayers
         //console.log('--- checkedLayers')
         return this.checkedLayers
      },

      relation: {
         get() {
            return this.modal.data.relation
         },
         set(value) {
            this.modal.data.relation = value
         }
      },

      reverse: {
         get() {
            return this.modal.data.reverse
         },
         set(value) {
            this.modal.data.reverse = value
         }
      },

   },
   watch: {
      updateHack(newValue, oldValue) {
         //console.log(`--- updateHack ${oldValue} <> ${newValue}`)
         if (oldValue !== newValue) {
            this.forceUpdateComponent()
         }
      }
   },
   mounted() {
      //console.log('=== mounted: init graph')
      this.initGraph()
      this.listenOnGraph()
      this.getRelationsList()

      this.canvas = document.getElementById('visgraph').querySelector('canvas')
      this.link = document.getElementById('exportCanvasBtn')
   },
   methods: {

      initGraph() {
         this.container = document.getElementById('visgraph')
         // Instanciate vis objects in separate window variables, see vis-network.js
         window.network = new vis.Network(this.container, this.visgraph_data, window.options)
      },
      forceUpdateComponent() {
         //console.log('!! forceUpdateComponent !!')
         this.refreshNetwork
         this.$forceUpdate()
      },

      // events
      listenOnGraph() {
         window.network.on('selectNode', (data) => {
            if (data.nodes.length > 1) {
               throw 'Multi selection is not allowed. Disable it in options.interaction !'
            }
            let node = data.nodes[0]
            let nodeType = splitId(node, 'type')
            switch (nodeType) {

               case 'person':
                  let person = this.nodes.filter(n => n.id === node)[0]
                  //console.log('@@@@@@ event on selected Node', person.id)
                  if (this.listenPersonFlag === 'normal') {
                     if (person.folded === true) {
                        //console.log('   @@> expand mode event')
                        this.$store.commit('unfoldPerson', person)
                     }
                  } else {
                     //console.log('   @@> create link mode event')
                     this.listenStepsToAddRelationship(person)
                  }
                  break

               case 'household':
                  let household = this.nodes.filter(n => n.id === node)[0]
                  //console.log('@@@@@@ event on selected Node', household.id)
                  this.$store.dispatch('unfoldPersonsByHousehold', household)
                  break

               case 'accompanying_period':
                  let course = this.nodes.filter(n => n.id === node)[0]
                  //console.log('@@@@@@ event on selected Node', course.id)
                  this.$store.dispatch('unfoldPersonsByCourse', course)
                  break

               default:
                  throw 'event is undefined for this type of node'
            }
            this.forceUpdateComponent()
         })
         window.network.on('selectEdge', (data) => {
            if (data.nodes.length !== 0 || data.edges.length !== 1) {
               return false  //we don't want to trigger nodeEdge or multiselect !
            }
            let link = data.edges[0]
            let linkType = splitId(link, 'link')
            //console.log('@@@@@ event on selected Edge', data.edges.length, linkType, data)

            if (linkType.startsWith('relationship')) {
               //console.log('linkType relationship')

               let relationships = this.edges.filter(l => l.id === link)
               if (relationships.length > 1) {
                  throw 'error: only one link is allowed between two person!'
               }

               let relationship = relationships[0]
               //console.log(relationship)

               this.editRelationshipModal({
                  from: relationship.from,
                  to: relationship.to,
                  id: relationship.id,
                  relation: relationship.relation,
                  reverse: relationship.reverse
               })
            }
         })
      },
      listenStepsToAddRelationship(person) {
         //console.log('   @@> listenStep', this.listenPersonFlag)
         if (this.listenPersonFlag === 'step2') {
            //console.log('   @@> person 2', person)
            this.newEdgeData.to = person.id
            this.addRelationshipModal(this.newEdgeData)
            this.displayHelpMessage = false
            this.listenPersonFlag = 'normal'
            this.newEdgeData = {}
         }
         if (this.listenPersonFlag === 'step1') {
            //console.log('   @@> person 1', person)
            this.newEdgeData.from = person.id
            this.listenPersonFlag = 'step2'
         }
      },

      /// control Layers
      toggleLayer(value) {
         let id = value.target.value
         //console.log('@@@@@@ toggle Layer', id)
         this.forceUpdateComponent()
         if (this.checkedLayers.includes(id)) {
            this.removeLayer(id)
         } else {
            this.addLayer(id)
         }
      },
      addLayer(id) {
         //console.log('+ addLayer', id)
         this.checkedLayers.push(id)
         this.$store.dispatch('excludedNode', ['remove', id])
      },
      removeLayer(id) {
         //console.log('- removeLayer', id)
         this.checkedLayers = this.checkedLayers.filter(i => i !== id)
         this.$store.dispatch('excludedNode', ['add', id])
      },

      /// control Modal
      addRelationshipModal(edgeData) {
         //console.log('==- addRelationshipModal', edgeData)
         this.modal = {
            data: { from:  edgeData.from, to: edgeData.to, reverse: false },
            action:  'create',
            showModal:  true,
            title:  'visgraph.add_relationship_link',
            button: { class:  'btn-create', text:  'action.create' }
         }
      },
      editRelationshipModal(edgeData) {
         //console.log('==- editRelationshipModal', edgeData)
         this.modal = {
            data: edgeData,
            action: 'edit',
            showModal: true,
            title: 'visgraph.edit_relationship_link',
            button: { class: 'btn-edit', text: 'action.edit' }
         }
      },

      // form
      resetForm() {
         this.modal = {
            data: { type: 'relationship', from: null, to: null, relation: null, reverse: false },
            action: null,
            title: null,
            button: { class: null, text: null, }
         }
         //console.log('==- reset Form', this.modal.data)
      },
      getRelationsList() {
         //console.log('fetch relationsList')
         return getRelationsList().then(relations => new Promise(resolve => {
            //console.log('+ relations list', relations.results.length)
            this.relations = relations.results.filter(r => r.isActive === true)
            resolve()
         })).catch()
      },
      customLabel(value) {
         //console.log('customLabel', value)
         return (value.title && value.reverseTitle) ? `${value.title.fr} ↔ ${value.reverseTitle.fr}` : ''
      },
      getPerson(id) {
         let person = this.persons.filter(p => p.id === id)
         return person[0]
      },
      getPersonAge(id) {
         let person = this.getPerson(id)
         return getAge(person)
      },

      // actions
      createRelationship() {
         this.displayHelpMessage = true
         this.listenPersonFlag = 'step1' // toggle listener in create link mode
         //console.log('   @@> switch listener to create link mode:', this.listenPersonFlag)
      },
      dropRelationship() {
         //console.log('delete', this.modal.data)
         deleteRelationship(this.modal.data)
            .catch()
         this.$store.commit('removeLink', this.modal.data.id)
         this.modal.showModal = false
         this.resetForm()
         this.forceUpdateComponent()
      },
      submitRelationship() {
         //console.log('submitRelationship', this.modal.action)
         switch (this.modal.action) {

            case 'create':
               return postRelationship(this.modal.data)
               .then(relationship => new Promise(resolve => {
                  //console.log('post relationship response', relationship)
                  this.$store.dispatch('addLinkFromRelationship', relationship)
                  this.modal.showModal = false
                  this.resetForm()
                  this.forceUpdateComponent()
                  resolve()
               }))
               .catch()

            case 'edit':
               return patchRelationship(this.modal.data)
               .then(relationship => new Promise(resolve => {
                  //console.log('patch relationship response', relationship)
                  this.$store.commit('updateLink', relationship)
                  this.modal.showModal = false
                  this.resetForm()
                  this.forceUpdateComponent()
                  resolve()
               }))
               .catch()

            default:
               throw "uncaught action"
         }
      },

      // export image
      async exportCanvasAsImage() {

         let
            filename = `filiation_${this.household_id}.jpg`,
            mime = 'image/jpeg',
            quality = 0.85,
            footer = `© Chill ${new Date().getFullYear()}`,
            timestamp = `${visMessages.fr.visgraph.relationship_household} n° ${this.household_id} — ${new Date().toLocaleString()}`

         // resolve toBlob in a Promise
         const getCanvasBlob = canvas => new Promise(resolve => {
            canvas.toBlob(blob => resolve(blob), mime, quality)
         })

         // build image from new temporary canvas
         let tmpCanvas = document.createElement('canvas')
         tmpCanvas.width = this.canvas.width
         tmpCanvas.height = this.canvas.height

         let ctx = tmpCanvas.getContext('2d')
         ctx.beginPath()
         ctx.fillStyle = '#fff'
         ctx.fillRect(0, 0, tmpCanvas.width, tmpCanvas.height);
         ctx.fillStyle = '#9d4600'
         ctx.fillText(footer +' — '+ timestamp, 5, tmpCanvas.height - 10)
         ctx.drawImage(this.canvas, 0, 0)

         return await getCanvasBlob(tmpCanvas)
            .then(blob => {
               let url = document.createElement("a")
               url.download = filename
               url.href = window.URL.createObjectURL(blob)
               url.click()
               console.log('url', url.href)
               URL.revokeObjectURL(url.href)
         })
      }

   }
}
</script>

<style src="vis-network/dist/dist/vis-network.min.css"></style>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

<style lang="scss" scoped>
div#visgraph {
   height: 700px;
   margin: auto;
}
div#visgraph-legend {
   div.post-menu.legend {
   }
}
.modal-mask {
   background-color: rgba(0, 0, 0, 0.25);
}
.debug {
   margin: 1em; padding: 1em;
   color: dimgray;
   font-style: italic;
   font-size: 80%;
}
</style>
