<script setup lang="ts">

import { ref, onMounted } from 'vue'
import HeaderBlock from './HeaderBlock.vue';
import { Network, type Data } from 'vis-network'
import { getGraph, updateNode } from './client';
import type { Graph, GraphApplication, GraphDoor, GraphEdge, GraphNode } from './models';

const network = ref<HTMLElement>()

const graph = ref<Graph>({
  nodes: [],
  edges: []
})

const emptyNode: GraphNode = {
  code: "",
  name: "",
  text: "",
  image: "",
  applications: [],
  hidden: false,
  doors: [],

  id: "",
  label: "",
  links: [],
}

const updatedNodeID = ref("")
const selectedNode = ref<GraphNode>({
  code: "",
  name: "",
  text: "",
  image: "",
  applications: [],
  hidden: false,
  doors: [],

  id: "",
  label: "",
  links: [],
})

const focusedNode = ref<GraphNode>({
  code: "",
  name: "",
  text: "",
  image: "",
  applications: [],
  hidden: false,
  doors: [],

  id: "",
  label: "",
  links: [],
})

let net = <Network>{}
let data = <Data>{}

const displayEdges = ref(0)
const allEdges = ref(0)
const isShowGraph = ref(false)
const onApplicationEdges = ref(true)

async function loadGraph() {
  graph.value = await getGraph()
  allEdges.value = graph.value.edges.length
  if (onApplicationEdges.value) {
    graph.value.edges = graph.value.edges.filter(function (edge: GraphEdge) { return edge.type !== 'application' })
  }
  graph.value.edges.map(function (edge: GraphEdge) {
    if (edge.type == 'application') {
      edge.color = '#aaaaaa'
    }
  })
  graph.value.nodes = graph.value.nodes.map(function (it: GraphNode) {
    it.id = it.code
    it.label = it.name
    return it
  })
  displayEdges.value = graph.value.edges.length
  data = {
    nodes: graph.value.nodes,
    edges: graph.value.edges.sort(function (a: GraphEdge, b: GraphEdge) {
      if (a.type == 'application') {
        return 1
      }
      if (b.type == 'application') {
        return -1
      }
      return 0
    })
  }
  net.setData(data)
  console.log(graph.value.edges)
}

onMounted(async () => {
  if (!network.value) return

  const options = {
    interaction: {
      selectable: true,
    },
    nodes: {
      color: {
        border: '#2B7CE9',           // Normal border color
        background: '#97C2FC',       // Normal background color
        highlight: {                 // Selection state
          border: '#960000',
          background: '#ff9494'
        },
        hover: {                     // Hover state
          border: '#2B7CE9',
          background: '#D2E5FF'
        }
      }
    },
  }
  net = new Network(network.value, data, options)
  net.on("click", function (params) {
    console.log("click graph:", params)
    if (params.nodes.length > 0) {
      const clickNode = graph.value.nodes.find(function (it: GraphNode): boolean { return it.code == params.nodes[0] })
      if (clickNode !== undefined) {
        selectNode(clickNode)
      }
    } else if (params.edges.length > 0) {
      console.log("Clicked edge:", params.edges[0]);
    }
  });

  await loadGraph()
  selectNode(graph.value.nodes[0])
})

function addApplicationToSelectedNode() {
  selectedNode.value.applications.push({ name: "" })
}

function removeApplicationToSelectedNode(name: string) {
  selectedNode.value.applications = selectedNode.value.applications.filter(function (it: GraphApplication): boolean { return it.name != name })
}

function addDoorToSelectedNode() {
  selectedNode.value.doors.push({ code: "", name: "", show: false })
}

function removeDoorToSelectedNode(code: string) {
  selectedNode.value.doors = selectedNode.value.doors.filter(function (it: GraphDoor): boolean { return it.code != code })
}

function selectNode(node: GraphNode) {
  console.log("Select node:", node)
  updatedNodeID.value = node.code
  selectedNode.value = node
  const links = graph.value.edges.filter(function (it: GraphEdge) {
    return it.from == node.code
  }).map(function (it: GraphEdge): GraphNode {
    const id = it.to
    const linkNode = graph.value.nodes.filter(function (it: GraphNode) { return it.code == id })
    return linkNode[0]
  })

  selectedNode.value.links = links
  net.selectNodes([selectedNode.value.code])
  if (!isShowGraph.value) {
    window.document.getElementById(node.code)?.scrollIntoView({ behavior: 'smooth', block: 'center' })
  }
}

function focusNode(node: GraphNode) {
  console.log("Focus node:", node.code)
  focusedNode.value = node
}

function copyLink(node: GraphNode) {
  console.log("Focus node:", node.code)
  navigator.clipboard.writeText("([" + node.code + "])")
  focusedNode.value = emptyNode
}

async function updateSelectedNode() {
  console.log("Update node:", selectedNode.value)
  await updateNode(updatedNodeID.value, selectedNode.value)
  await loadGraph()

  const nodes = graph.value.nodes.filter(function (it: GraphNode) {
    return it.code == selectedNode.value.code
  })
  selectNode(nodes[0])
}

async function deleteSelectedNode() {
  console.log("Delete node:", selectedNode.value)
  selectedNode.value.code = ""
  await updateNode(updatedNodeID.value, selectedNode.value)
  await loadGraph()
}

async function addSelectedNode() {
  console.log("Add node:", selectedNode.value)
  selectedNode.value.code = updatedNodeID.value
  await updateNode("", selectedNode.value)
  await loadGraph()

  const nodes = graph.value.nodes.filter(function (it: GraphNode) {
    return it.code == selectedNode.value.code
  })
  selectNode(nodes[0])
}

function nodeHeader(node: GraphNode): string {
  return "[" + node.code + "] - " + node.name
}

function showGraph(show: boolean) {
  isShowGraph.value = show
  if (isShowGraph.value) {
    loadGraph()
  }
}
</script>

<template>
  <HeaderBlock>
    <div>
      Редактор сценариев
    </div>
  </HeaderBlock>

  <div :class="[isShowGraph ? 'text-container-disable' : '']">
    <div class="data-container text-container">
      <!-- Действия -->
      <div class="messages-block" ref="scrollContainer">
        <div class="center-block-custom">
          <div v-for="action in graph.nodes" :key="action.id" v-on:click="selectNode(action)" :id="action.code">
            <div class="message-cloud" :class="[action.code == selectedNode.code ? 'selected-message-cloud' : '']">
              <div class="message-header" :class="[action.code == selectedNode.code ? 'selected-message-header' : '']">
                {{ action.code }}: {{ action.name }}
              </div>
              <div v-if="action.image !== ''">
                {{ action.image }}
              </div>
              <hr class="hr" />
              <div class="message-content">
                {{ action.text }}
              </div>
              <hr class="hr" v-if="action.applications.length" />
              <div class="message-footer" v-for="door in action.doors" :key="door.code">
                <span v-if="door.show">Кнопка: </span>
                <span v-if="!door.show">Дверь: </span>
                [{{ door.code }}] - "{{ door.name }}"
              </div>
              <div class="message-footer" v-for="application in action.applications" :key="application.name">
                Приложение: {{ application.name }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div :class="[!isShowGraph ? 'graph-container-disable' : '']">
    <div ref="network" class="data-container graph-container"></div>
  </div>

  <div class="nodes-container">
    <h2>Точки</h2>
    <div>Всего точек: {{ graph.nodes.length }}</div>
    <div>
      Отображать граф:
      <label class="checkbox-green">
        <input type="checkbox" v-on:click="showGraph(!isShowGraph)">
        <span class="checkbox-green-switch" data-label-on="Да" data-label-off="Нет"></span>
      </label>
    </div>
    <div>
      Всего связей: {{ allEdges }}, показано: {{ displayEdges }}
      <div>
        Показать все связи:
        <label class="checkbox-green">
          <input type="checkbox" v-on:click="onApplicationEdges = !onApplicationEdges, loadGraph()">
          <span class="checkbox-green-switch" data-label-on="Да" data-label-off="Нет"></span>
        </label>
      </div>
    </div>

    <hr class="hr">

    <div class="scroll-y">
      <div v-bind:key="node.code" v-for="node in graph.nodes">
        <span v-on:mouseenter="focusNode(node)" v-on:mouseleave="focusNode(emptyNode)">
          <span :class="[node.code == selectedNode.code ? 'selected-node' : '']" class="node-select-button"
            v-on:click="selectNode(node)">{{ nodeHeader(node) }}</span>
          <span v-if="node.applications.length > 0"> ({{ node.applications.length }})</span>
          <span v-if="node.code == focusedNode.code" class="copy-node-link" v-on:click="copyLink(node)">
            Ссылка
          </span>
        </span>
      </div>
    </div>
  </div>

  <div class="edit-node-container">
    <div class="scroll-y-right">
      <h2>Редактирование точки</h2>
      <div>
        <input v-model="updatedNodeID" type="text" class="node-code-edit-field" maxlength="5" /> - <input
          v-model="selectedNode.name" type="text" class="node-name-edit-field" />
      </div>
      <div>
        <textarea class="node-text-edit-field" rows="15" v-model="selectedNode.text"></textarea>
      </div>
      <div>
        <h3>Двери: {{ selectedNode.doors.length }}
          <button class="editor-button application-add-button" v-on:click="addDoorToSelectedNode()">+</button>
        </h3>
        <div class="tb-5" v-if="selectedNode.doors.length > 0">
          <div v-bind:key="index" v-for="(door, index) in selectedNode.doors">
            <button class="editor-button application-remove-button"
              v-on:click="removeDoorToSelectedNode(door.code)">-</button>
            <input class="node-code-edit-field" v-model="door.code" type="text" maxlength="5" /> -
            <input class="node-name-edit-field" v-model="door.name" type="text" /> -
            <input class="node-code-edit-field" v-model="door.show" type="text" maxlength="5" />
          </div>
        </div>
      </div>
      <div>
        <h3>Приложения: {{ selectedNode.applications.length }}
          <button class="editor-button application-add-button" v-on:click="addApplicationToSelectedNode()">+</button>
        </h3>
        <div v-bind:key="index" v-for="(application, index) in selectedNode.applications">
          <button class="editor-button application-remove-button"
            v-on:click="removeApplicationToSelectedNode(application.name)">-</button>
          <textarea class="node-text-edit-field" rows="2" v-model="application.name"></textarea>
        </div>
      </div>
      <div>
        <h3>Ссылки: {{ selectedNode.links.length }}</h3>
        <div v-bind:key="node.code" v-for="node in selectedNode.links">
          <div class="node-select-button" v-on:click="selectNode(node)">
            - {{ nodeHeader(node) }}
          </div>
        </div>
      </div>
      <div>
        <hr class="hr">
        <div>
          <button class="editor-button" v-on:click="updateSelectedNode()">Сохранить</button>
          <button class="editor-button" v-on:click="addSelectedNode()">Добавить</button>
          <button class="editor-button" v-on:click="deleteSelectedNode()">Удалить</button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.data-container {
  width: 100%;
  height: calc(100vh - 50px);
  border: 1px solid #e0e0e0;
}

.graph-container {
  border-radius: 8px;
}

.graph-container-disable {
  position: absolute;
  right: 10000px;
}

.text-container {
  padding: 10px;
  /* background-color: red; */
}

.text-container-disable {
  position: absolute;
  left: 10000px;
}

.nodes-container {
  position: fixed;
  left: 5px;
  top: 55px;
  height: calc(100vh - 100px);
  padding: 3px 10px;
}

.edit-node-container {
  position: fixed;
  right: 5px;
  top: 55px;
  height: calc(100vh - 100px);
  padding: 3px 10px;
  min-width: 350px;
  max-width: 400px;
}

.node-select-button {
  color: #373737;
}

.node-select-button:hover {
  font-weight: bold;
  cursor: pointer;
}

.selected-node {
  font-weight: bold;
  color: #960000;
  cursor: pointer;
}

.node-text-edit-field {
  padding: 7px;
  margin: 5px 0;
  width: 100%;
}

.editor-button {
  padding: 3px 7px;
  margin: 5px 5px 5px 0;
  background-color: #ffffff;
  border: 1px solid #777777;
}

.editor-button:hover {
  background-color: #eeeeee;
  cursor: pointer;
}

.hr {
  margin: 10px 0;
}

.copy-node-link {
  margin-left: 5px;
}

.copy-node-link:hover {
  font-weight: bold;
  cursor: pointer;
}

.scroll-y {
  overflow-y: auto;
  max-height: calc(100vh - 250px);
}

.scroll-y-right {
  overflow-y: auto;
  max-height: calc(100vh - 70px);
}

.scroll-y::-webkit-scrollbar,
.scroll-y-right::-webkit-scrollbar {
  display: none;
}

.node-code-edit-field {
  width: 50px;
}

.node-name-edit-field {
  width: 200px;
}

.application-add-button {
  display: inline;
  margin-left: 5px;
  width: 23px;
  height: 23px;
}

.application-remove-button {
  position: absolute;
  left: -15px;
  width: 20px;
  height: 20px;
}


.messages-block {
  height: 100%;
  overflow-y: auto;
  scrollbar-width: none;
}

@media (min-width: 1025px) {
  .center-block-custom {
    width: calc(100vw - 750px);
    margin: 0 auto;
  }
}

.message-cloud {
  border: 1px solid #444444;
  border-radius: 15px;
  margin: 12px 10px;
  padding: 16px;
  background-color: var(--main-back-item-color);
}

.message-cloud:hover {
  background-color: #eeeeee;
  cursor: pointer;
}

.selected-message-cloud {
  border: 2px solid #960000;
  cursor: pointer;
}

.message-header {
  font-size: large;
  font-weight: 200;
}

.selected-message-header {
  font-size: large;
  font-weight: 500;
  color: #960000;
}

.message-content {
  font-weight: 500;
  /* white-space: pre-line; */
  white-space: pre-wrap;
}

.message-footer {
  font-weight: 400;
  color: var(--second-color);
}


.checkbox-green {
  display: inline-block;
  height: 20px;
  line-height: 28px;
  margin-right: 10px;
  position: relative;
  vertical-align: middle;
  font-size: 14px;
  user-select: none;
}

.checkbox-green .checkbox-green-switch {
  display: inline-block;
  height: 20px;
  width: 90px;
  box-sizing: border-box;
  position: relative;
  border-radius: 2px;
  background: #848484;
  transition: background-color 0.3s cubic-bezier(0, 1, 0.5, 1);
}

.checkbox-green .checkbox-green-switch:before {
  content: attr(data-label-on);
  display: inline-block;
  box-sizing: border-box;
  width: 45px;
  padding: 0 8px;
  position: absolute;
  top: 0;
  left: 45px;
  text-transform: uppercase;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 10px;
  line-height: 20px;
}

.checkbox-green .checkbox-green-switch:after {
  content: attr(data-label-off);
  display: inline-block;
  box-sizing: border-box;
  width: 44px;
  border-radius: 1px;
  position: absolute;
  top: 1px;
  left: 1px;
  z-index: 5;
  text-transform: uppercase;
  text-align: center;
  background: white;
  line-height: 18px;
  font-size: 10px;
  color: #444444;
  transition: transform 0.3s cubic-bezier(0, 1, 0.5, 1);
}

.checkbox-green input[type="checkbox"] {
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  z-index: -1;
  opacity: 0;
}

.checkbox-green input[type="checkbox"]:checked+.checkbox-green-switch {
  background-color: #777777;
}

.checkbox-green input[type="checkbox"]:checked+.checkbox-green-switch:before {
  content: attr(data-label-off);
  left: 0;
}

.checkbox-green input[type="checkbox"]:checked+.checkbox-green-switch:after {
  content: attr(data-label-on);
  color: #777777;
  transform: translate3d(44px, 0, 0);
}

/* Hover */
.checkbox-green input[type="checkbox"]:not(:disabled)+.checkbox-green-switch:hover {
  cursor: pointer;
}

/* Disabled */
.checkbox-green input[type=checkbox]:disabled+.checkbox-green-switch {
  opacity: 0.6;
  filter: grayscale(50%);
}

/* Focus */
.checkbox-green.focused .checkbox-green-switch:after {
  box-shadow: inset 0px 0px 4px #ff5623;
}

.tb-5 {
  margin: 5px 0;
}
</style>
