<template>
  <div class="mechanisms">
    <div class="add-section">
      <div>
        <div class="add-group-wrap">
          <div class="add-group" v-for="(item, index) in mechanism" :key="index">
            <input type="text" v-model.trim="item.name" placeholder="Nosaukums" />
            <input type="text" v-model.trim="item.unit_of_measurement" placeholder="Mērvienība" />
            <input type="text" v-model.trim="item.manufacturer_name" placeholder="Izstrādātājs" />
            <input type="number" v-model.trim="item.amount" placeholder="Daudzums" />
            <input type="number" v-model.trim="item.price" placeholder="Cena (EUR)" />
            <button class="btn-round-big btn-red" v-show="mechanism.length > 1" @click="minusMechanism(index)">-</button>
          </div>
        </div>
        <button class="btn-round-big btn-blue" @click="addMechanism">+</button>
        <button class="btn btn-green border-def" @click="createMechanism">Pievienot</button>
      </div>
      <div class="error-block" v-if="errors.createMechanism.display" style="display: block;" @click="hideError('createMechanism')"><span>{{ errors.createMechanism.message }}</span></div>
      <div class="search-group-wrap">
        <div class="search-group" v-for="(field, index) in search" :key="index">
          <input type="text" v-model.trim="field.query" placeholder="Meklēt...">
          <select v-model="field.property" v-if="mechanismsWithSums.length > 0">
            <option v-for="(key, index) in Object.keys(mechanismsWithSums[0])" :key="index" :value="key">{{ properties[key] }}</option>
          </select>
          <button class="btn-round-big btn-red" v-show="search.length > 1" @click="removeQuery(index)">-</button>
        </div>
      </div>
      <button class="btn-round-big btn-blue" @click="addQuery">+</button>
    </div>
    <div v-if="mechanisms.length > 0">
      <div class="overflow-x-wrapper">
        <table class="main">
          <tr>
            <th>
              <input
              type="checkbox"
              v-model="checkedAll"
              @change="checkedAll ? checkedItems = filtered.map(x => x.id) : checkedItems = []">
            </th>
            <th
            class="sortable"
            @click="changeSort('name')"
            :class="{ sorted: sort.property === 'name' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Nosaukums
            </th>
            <th
            class="sortable"
            @click="changeSort('unit_of_measurement')"
            :class="{ sorted: sort.property === 'unit_of_measurement' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Mērvienība
            </th>
            <th
            class="sortable"
            @click="changeSort('manufacturer_name')"
            :class="{ sorted: sort.property === 'manufacturer_name' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Izstrādātājs
            </th>
            <th
            class="sortable"
            @click="changeSort('amount')"
            :class="{ sorted: sort.property === 'amount' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Daudzums
            </th>
            <th
            class="sortable"
            @click="changeSort('price')"
            :class="{ sorted: sort.property === 'price' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Cena (EUR)
            </th>
            <th
            class="heading-light sortable"
            @click="changeSort('sum')"
            :class="{ sorted: sort.property === 'sum' && !sort.disabled, asc: sort.asc, desc: !sort.asc }">
              Summa (EUR)
            </th>
          </tr>
          <tr v-for="item in filtered" :key="item.id">
            <td>
              <input
              type="checkbox"
              :value="item.id"
              v-model="checkedItems"
              @change="checkedItems.length === filtered.length ? checkedAll = true : checkedAll = false">
            </td>
            <template v-if="!checkedItems.includes(item.id)">
              <td>
                <router-link :to="{ name: 'Mechanism', params: { id: item.id } }">
                  {{ !edited[item.id] ? item.name : edited[item.id].name || item.name }}
                </router-link>
                <button class="copy-btn" @click="copy(item.id)">Kopēt</button>
              </td>
              <td v-for="(key, index) in ['unit_of_measurement', 'manufacturer_name', 'amount', 'price']" :key="index">
                {{ !edited[item.id] ? item[key] : edited[item.id][key] || item[key] }}
                <button class="copy-btn" @click="copy(item[key])" v-show="!checkedItems.includes(item.id)">Kopēt</button>
              </td>
            </template>
            <template v-else>
              <td v-for="(key, index) in ['name', 'unit_of_measurement', 'manufacturer_name', 'amount', 'price']" :key="index">
                <input
                :type="typeof item[key] === 'number' ? 'number' : 'text'"
                :value="!edited[item.id] ? item[key] : edited[item.id][key] || item[key]"
                @input="addToEdited(item, key, $event.target.value)">
              </td>
            </template>
            <td>
              {{ item.sum }}
              <button class="copy-btn" @click="copy(item.sum)">Kopēt</button>
            </td>
          </tr>
        </table>
      </div>
      <button
      class="btn btn-green border"
      @click="updateMechanism"
      :disabled="checkedItems.length === 0">
        Saglabāt
      </button>
      <button
      class="btn btn-yellow border"
      @click="edited = {}; checkedItems = []; checkedAll = false"
      :disabled="checkedItems.length === 0">
        Atcelt
      </button>
      <button
      class="btn btn-red border"
      @click="deleteMechanism(checkedItems)"
      :disabled="checkedItems.length === 0">
        Dzēst
      </button>
      <div class="dropdown" v-if="mechanisms.length > 0">
        <button class="btn btn-green border">
          Eksportēt
        </button>
        <ul class="dropdown-data">
          <a
          :href="'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(mechanisms))"
          :download="'mechanisms-' + Date.now() + '.json'">
            <li>
              JSON
            </li>
          </a>
          <a
          :href="'data:text/csv;charset=utf-8,' + encodeURIComponent(mechanismsToCSV())"
          :download="'mechanisms-' + Date.now() + '.csv'">
            <li>
              CSV
            </li>
          </a>
        </ul>
      </div>
      <div class="dropdown">
        <button class="btn btn-green border" @click="openImportDropdown($event.target)" ref="importMenu">
          Importēt
        </button>
        <div class="dropdown-data" :style="dropdownStyle" @click="$refs.importMenu.focus()">
          <div class="tab-bar">
            <button
            v-for="(tab, index) in tabs.import.tabs"
            :class="{ 'active': tabs.import.tabs.active === index }"
            @click="$set(tabs.import.tabs, 'active', index)"
            :key="index">
              {{ tab }}
            </button>
          </div>
          <div class="tab-data" v-show="tabs.import.tabs.active === 0">
            <input type="file" ref="uploadJSON" accept=".json">
            <div class="error-block" v-if="errors.uploadJSON.display" @click="hideError('uploadJSON')"><span>{{ errors.uploadJSON.message }}</span></div>
            <button class="btn btn-green border" @click="uploadJSON()">
              Ielādēt
            </button>
          </div>
          <div class="tab-data" v-show="tabs.import.tabs.active === 1">
            <input type="file" ref="uploadCSV" accept=".csv">
            <div class="error-block" v-if="errors.uploadCSV.display" @click="hideError('uploadCSV')"><span>{{ errors.uploadCSV.message }}</span></div>
            <button class="btn btn-green border" @click="uploadCSV()">
              Ielādēt
            </button>
          </div>
        </div>
      </div>
    </div>
    <div v-else>
      <h1>Nav neviena vienuma.</h1>
      <h2>Pievienojiet jaunu mehānismu.</h2>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    mechanisms: Array,
    properties: Object
  },
  data() {
    return {
      mechanism: [{name: "", unit_of_measurement: "", manufacturer_name: "", amount: null, price: null}],
      edited: {},
      checkedAll: false,
      checkedItems: [],
      dropdownStyle: {
        right: 0,
        transform: 'none'
      },
      tabs: {
        import: {
          tabs: ['JSON', 'CSV'],
          active: 0
        }
      },
      search: [{ query: '', property: 'name' }],
      sort: {
        property: 'name',
        asc: true,
        disabled: true
      },
      errors: (function () {
        const errorNames = ['createMechanism', 'uploadJSON', 'uploadCSV'];
        const errors = {};
        errorNames.forEach(x => errors[x] = { message: '', display: false });
        return errors;
      })()
    };
  },
  computed: {
    mechanismsWithSums() {
      const mechanisms = JSON.parse(JSON.stringify(this.mechanisms));
      for (const mechanism of mechanisms) mechanism.sum = +(Math.ceil(mechanism.amount * mechanism.price + "e+2") + "e-2");
      return mechanisms;
    },
    filtered() {
      return this.mechanismsWithSums
        .filter(x => this.search
        .every(field => field.query.split(',')
        .some(keyword => x[field.property].toString().toLowerCase()
        .includes(keyword.toLowerCase().trim()))))
        .sort((a, b) => {
          const { property, asc, disabled } = this.sort;
          if (disabled) return 0;
          if (asc) {
            if (a[property] < b[property]) return -1;
            else if (a[property] > b[property]) return 1;
            else return 0;
          }
          if (a[property] > b[property]) return -1;
          else if (a[property] < b[property]) return 1;
          else return 0;
        });
    }
  },
  methods: {
    addToEdited(item, key, value) {
      if (item[key] !== value && (key === 'manufacturer_name' || value.trim())) {
        if (!(item.id in this.edited)) this.edited[item.id] = {};
        this.edited[item.id][key] = value;
      } else {
        if (item.id in this.edited) {
          delete this.edited[item.id][key];
          if (Object.keys(this.edited[item.id]).length === 0) {
            delete this.edited[item.id];
          }
        }
      }
    },
    async createMechanism() {
      const items = this.mechanism.filter(x => x.name !== '' && x.unit_of_measurement !== '' && x.amount && x.price);
      if (this.mechanism.length > items.length && items.length > 0) {
        this.graphqlMutation(items, 'create');
        const names = items.map(x => x.name);
        this.mechanism = this.mechanism.filter(x => !names.includes(x.name));
        this.displayError('createMechanism', `Pievienoti ${items.length} no ${this.mechanism.length} vienumiem`);
      } else if (items.length === 0) {
        if (this.mechanism.some(x => x.name !== '' || x.unit_of_measurement !== '' || x.amount || x.price))
        this.displayError('createMechanism', `Vienums netika pievienots. Pārliecinieties, lai visi lauki būtu aizpildīti!`);
      } else {
        this.hideError('createMechanism');
        this.graphqlMutation(items, 'create');
        this.mechanism = [{name: "", unit_of_measurement: "", manufacturer_name: "", amount: null, price: null}];
      }
    },
    addMechanism() {
      this.mechanism.push({name: "", unit_of_measurement: "", manufacturer_name: "", amount: null, price: null});
    },
    minusMechanism(index) {
      this.mechanism.splice(index, 1);
    },
    async updateMechanism() {
      const temp = [];
      for (const [key, value] of Object.entries(this.edited)) {
        temp.push({id: key, ...value})
      }
      const items = temp.filter(x => this.checkedItems.includes(x.id));
      if (items.length > 0) this.graphqlMutation(items, 'update');
      this.edited = {};
      this.checkedItems = [];
      this.checkedAll = false;
    },
    async deleteMechanism(ids) {
      this.graphqlMutation(ids, 'delete');
      this.checkedItems = [];
      this.checkedAll = false;
    },
    graphqlMutation(items, operation) {
      this.$emit('graphql-mutation', { items, operation, type: 'Mechanism' });
    },
    copy(text) {
      navigator.clipboard.writeText(text).catch(error => {
        console.error(error);
      });
    },
    mechanismsToCSV() {
      const { mechanisms } = this;
      const header = Object.keys(mechanisms[0]);
      const csv = [
        header.join(';'),
        ...mechanisms.map(row => header.map(fieldName => {
          return row[fieldName];
        }).join(';'))
      ].join('\r\n');
      return csv;
    },
    uploadJSON() {
      const fileReader = new FileReader();
      const graphqlMutation = (input, operation) => this.graphqlMutation(input, operation);
      fileReader.onload = function(event) {
        const result = JSON.parse(event.target.result);
        const allowedFields = ['id', 'name', 'unit_of_measurement', 'manufacturer_name', 'amount', 'price'];
        result.forEach(row => {
          for (const key of Object.keys(row)) {
            if (!allowedFields.includes(key)) delete row[key];
          }
        });
        graphqlMutation(result, 'create', 'Mechanism');
      };
      if (this.$refs.uploadJSON.files.length > 0) {
        this.hideError('uploadJSON');
        fileReader.readAsText(this.$refs.uploadJSON.files[0]);
      }
      else this.displayError('uploadJSON', 'Pievienojiet failu');
    },
    uploadCSV() {
      const fileReader = new FileReader();
      const graphqlMutation = (input, operation) => this.graphqlMutation(input, operation);
      fileReader.onload = function(event) {
        const result = event.target.result;
        const rows = result.split('\r\n');
        const header = rows[0].split(';');
        rows.splice(0, 1);
        const resultArr = [];
        rows.forEach(row => {
          const splitRow = row.split(';');
          const rowObj = {};
          for (let i = 0; i < splitRow.length; i++) {
            rowObj[header[i]] = splitRow[i];
          }
          resultArr.push(rowObj);
        });
        const allowedFields = ['id', 'name', 'unit_of_measurement', 'manufacturer_name', 'amount', 'price'];
        resultArr.forEach(row => {
          for (const [key, value] of Object.entries(row)) {
            if (!allowedFields.includes(key)) delete row[key];
            if (value === '') row[key] = null;
          }
        });
        graphqlMutation(resultArr, 'create', 'Mechanism');
      };
      if (this.$refs.uploadCSV.files.length > 0) {
        this.hideError('uploadCSV');
        fileReader.readAsText(this.$refs.uploadCSV.files[0]);
      }
      else this.displayError('uploadCSV', 'Pievienojiet failu');
    },
    addQuery() {
      this.search.push({ query: '', property: 'name' });
    },
    removeQuery(index) {
      this.search.splice(index, 1);
    },
    changeSort(property) {
      if (this.sort.property === property && !this.sort.asc && !this.sort.disabled) {
        this.sort.disabled = true;
      } else if (this.sort.disabled) {
        this.sort.property = property;
        this.sort.asc = true;
        this.sort.disabled = false;
      } else {
        if (this.sort.property === property) this.sort.asc = !this.sort.asc;
        else this.sort.property = property;
      }
    },
    displayError(errorName, message) {
      for (const key of Object.keys(this.errors)) {
        this.errors[key].display = false;
      }
      this.errors[errorName].message = message;
      this.errors[errorName].display = true;
    },
    hideError(errorName) {
      if (this.errors[errorName].display) this.errors[errorName].display = false;
    },
    openImportDropdown(target) {
      this.$set(this.tabs.import.tabs, 'active', this.tabs.import.tabs.active || 0);

      const rect = target.getBoundingClientRect();
      const left = window.scrollX + rect.left; //pogas attālums no kreisās puses
      const right = window.scrollX + (window.innerWidth - rect.right); //pogas attālums no labās puses
      const { dropdownStyle: style } = this;

      if (left + rect.width - 200 <= 0 && right + rect.width - 200 <= 0) { //izvēlne atrodas vidū
        style.right = '50%';
        style.transform = 'translate(50%, 0)';
      } else if (left + rect.width - 200 <= 0) { //izvēlne atrodas labajā pusē
        style.transform = 'none';
        style.right = 'unset';
      } else if (right + rect.width - 200 <= 0) { //izvēlne atrodas kreisajā pusē
        style.transform = 'none';
        style.right = '0';
      } else { 
        style.transform = 'none';
        style.right = '0';
      }

      this.dropdownStyle = style;
    }
  }
}
</script>