<template>
  <v-app>
    <v-container>
      <v-data-table-server
        :headers="encabezados"
        :items="configuraciones"
        :items-length="totalConfiguraciones"
        :loading="obteniendoConfiguraciones"
        item-value="id"
        @update:options="obtenerConfiguracionesDesdeServer"
        v-model:items-per-page="configuracionesPorPagina"
        v-model:page="paginaSeleccionada"
      >
        <template v-slot:top>
          <v-row justify="space-between" class="ma-0">
            <v-col cols="auto"><h1>Variables de configuración del sistema</h1></v-col>
            <v-col cols="auto">
              <v-tooltip text="Crea una nueva configuración del sistema">
                <template v-slot:activator="{ props }">
                  <v-btn v-bind="props" text="Agregar" prepend-icon="mdi-plus" color="success" @click="mostrarFormulario=true"/>
                </template>
              </v-tooltip>
            </v-col>
          </v-row>
          <v-row dense justify="center" align="center" class="mx-3">
            <v-col cols="12" sm="5" md="6">
              <v-text-field
                density="compact"
                label="Buscar"
                :hide-details="true"
                v-model="configuracionBusqueda.buscar"
                prepend-inner-icon="mdi-text-search-variant" />
            </v-col>
            <v-col cols="12" sm="4" md="4">
              <v-select
                density="compact"
                label="En"
                :hide-details="true"
                v-model="configuracionBusqueda.campo"
                :items="['Configuración', 'Descripción', 'Actualización', 'Tags']"/>
            </v-col>
            <v-col cols="12" sm="3" md="2">
              <v-btn
                text="Aplicar"
                color="info"
                block
                @click="buscarEnConfiguraciones()"
                append-icon="mdi-filter-check" />
            </v-col>
          </v-row>
          <v-row class="mx-3" align="start" justify="start" align-content="start">
            <v-col v-for="(filtro, index) in filtros">
              <v-chip color="warning">
                filtrando {{filtro.buscar}} en {{filtro.campo}}
                <v-icon icon="mdi-close-circle" class="ml-1" @click="eliminarFiltro(index)"/>
              </v-chip>
            </v-col>
          </v-row>
        </template>
        <template v-slot:no-data>
          <v-empty-state
            headline="Sin configuraciones"
            text="Crea una nueva configuración en el botón AGREGAR"
            title="Las configuraciones del sistema aparecerán aquí"
          ></v-empty-state>
        </template>

        <!-- CELDA DE DESCRIPCION -->
        <template #item.descripcion="{ item }">
          <span>{{ item.descripcion.length > 20 ? item.descripcion.substring(0, 20) + '...' : item.descripcion }}</span>
          <VTooltip activator="parent" max-width="300px">
            {{ item.descripcion }}
          </VTooltip>
        </template>
        <!-- /CELDA DE DESCRIPCION -->

        <!-- CELDA DE VALOR -->
        <template #item.valor="{ item }">

          <div v-if="item.tipo === 'selector-color'">
            <v-avatar :color="item.valor"></v-avatar>
            {{item.valor}}
          </div>

          <div v-else-if="item.tipo === 'imagen'">
              <v-card elevation="2" rounded>
                <a :href="buildStorageUrl(item.valor)" target="_blank">
                  <v-img :src="buildStorageUrl(item.valor)" height="64" cover></v-img>
                </a>
              </v-card>
          </div>

          <div v-else-if="item.tipo === 'archivo'">
            <v-btn icon="mdi-file-download-outline" :href="buildStorageUrl(item.valor)" target="_blank"></v-btn>
          </div>

          <div v-else-if="item.tipo === 'texto' || item.tipo === 'textarea'">
            <span>{{ item.valor.length > 20 ? item.valor.substring(0, 20) + '...' : item.valor }}</span>
            <VTooltip activator="parent" max-width="300px">
              {{ item.valor }}
            </VTooltip>
          </div>
          <div v-else>
            {{item.valor}}
          </div>
        </template>
        <!-- /CELDA DE VALOR -->

        <!-- CELDA DE TAGS-->
        <template v-slot:item.tags="{ item }">
            <v-chip v-if="item.tags"
              :text="item.tags"
              color="success"
              class="text-uppercase"
              size="small"
              label
            ></v-chip>
        </template>
        <!-- /CELDA DE TAGS-->

        <!-- CELDA DE ACCIONES -->
        <template v-slot:[`item.actions`]="{ item }">
          <v-menu>
            <template v-slot:activator="{ props }">
              <v-btn
                icon="mdi-dots-vertical"
                variant="text"
                v-bind="props"
              ></v-btn>
            </template>
            <v-list>
              <v-list-item>
                <v-list-item-title>
                  <v-tooltip text="Editar definición">
                    <template v-slot:activator="{ props }">
                      <v-btn v-bind="props" icon="mdi-cog-sync-outline" variant="text" size="small" color="warning" @click="editarConfiguracion(item)"/>
                    </template>
                  </v-tooltip>
                </v-list-item-title>
                <v-list-item-title>
                  <v-tooltip text="Eliminar configuración">
                    <template v-slot:activator="{ props }">
                      <v-btn v-bind="props" icon="mdi-delete" variant="text" size="small" color="error" @click="dispararEliminarConfiguracion(item)"/>
                    </template>
                  </v-tooltip>
                </v-list-item-title>
                <v-list-item-title>
                  <v-tooltip text="Cambiar valor">
                    <template v-slot:activator="{ props }">
                      <v-btn v-bind="props" icon="mdi-pencil-outline" variant="text" size="small" color="secondary" @click="dispararActualizarValor(item)"/>
                    </template>
                  </v-tooltip>
                </v-list-item-title>
              </v-list-item>
            </v-list>
          </v-menu>
        </template>
        <!-- /CELDA DE ACCIONES -->

      </v-data-table-server>
    </v-container>
    <v-dialog
      v-model="mostrarFormulario"
      @update:modelValue="onModalClosed"
      max-width="600"
      z-index="2000"
    >
      <v-card
        prepend-icon="mdi-cogs"
        :title="`${data.id ? 'Editar' : 'Crear'} Configuración`"
      >
        <v-card-text>
          <v-row dense>
            <v-col
              cols="12"
            >
              <v-text-field
                label="Nombre*"
                hint="Nombre de la configuración"
                required
                v-model="data.nombre"
                counter="125"
                persistent-counter
                :rules="[v => !!v || 'Debes poner un nombre de variable', v => v.length<126||'Máximo 125 caracteres']"
              />
            </v-col>

            <v-col
              cols="12"
            >
              <v-text-field
                hint="identificador único (autogenerado)"
                label="Identificador"
                v-model="data.identificador"
                readonly
                tabindex="-1"
              />
            </v-col>

            <v-col
              cols="12"
            >
              <v-text-field
                hint="Descripción"
                label="Descripción*"
                v-model="data.descripcion"
              />
            </v-col>

            <v-col
              cols="12"
            >
              <v-select
                hint="tipo de dato a guardar"
                label="tipo*"
                persistent-hint
                required
                :items="['texto','textarea','numeric-input','imagen','archivo','rango','select-one','select', 'selector-color']"
                v-model="data.tipo"
                @update:model-value="setBaseLayout"
              />
            </v-col>

            <v-col
              cols="12"
            >
              <v-textarea
                label="opciones*"
                v-model="data.opciones"
              />
            </v-col>

            <v-col
              cols="12"
            >
              <v-form>
                <vjsf v-model="data" :schema="schema" :options="options"/>
              </v-form>
            </v-col>

            <v-col
              cols="12"
            >
              <v-text-field
                label="tags"
                v-model="data.tags"
              />
            </v-col>
            <small class="text-caption text-medium-emphasis">los campos marcados con  (*) son obligatorios</small>
          </v-row>
        </v-card-text>

        <v-divider></v-divider>
        <v-alert
          v-model="mostrarAlerta"
          border="start"
          close-label="cerrar"
          color="error"
          title="Ha ocurrido un error"
          :text="mensajeDeError"

          variant="tonal"
          closable

        >
        </v-alert>
          {{mensajeDeError}}
        <v-card-actions>
          <v-spacer></v-spacer>

          <v-btn
            text="Cancelar"
            variant="plain"
            @click="cancelarFormularioConfiguracion"
          ></v-btn>

          <v-btn
            color="primary"
            :text="`${data.id ? 'Actualizar' : 'Guardar'}`"
            variant="tonal"
            @click="data.id ? actualizarConfiguracion() : guardarConfiguracion()"
            :loading="estaGuandadoConfiguracion"
          ></v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
    <v-snackbar
      v-model="mostrarExito"
      timeout="2500"
      color="success"
    >
      <v-alert
        text="Operación realizada con éxito"
        title="¡Hecho!"
        type="success"
      ></v-alert>

      <template v-slot:actions>
        <v-btn
          color="secondary"
          variant="text"
          @click="mostrarExito = false"
        >
          Cerrar
        </v-btn>
      </template>
    </v-snackbar>
    <v-dialog
      v-model="confirmacionEliminar"
      max-width="400"
      persistent
    >
      <v-card
        text="¿Desea eliminar esta variable del sistema? Esta acción no puede recuperarse."
        title="Confirmación de eliminación"
      >
        <template v-slot:prepend>
          <v-icon icon="mdi-alert" color="warning"/>
        </template>
        <template v-slot:actions>
          <v-spacer></v-spacer>
          <v-btn @click="cancelarEliminacion" color="secondary" variant="tonal">
            No, cancelar
          </v-btn>
          <v-btn @click="eliminarConfiguracion" :loading="seEstaEliminando" color="error" variant="tonal">
            Si, eliminar
          </v-btn>
        </template>
      </v-card>
    </v-dialog>
    <v-dialog
      v-model="actualizarValor"
      max-width="800"
      persistent
      z-index="2000"
    >
      <v-confirm-edit v-model="data">
        <template v-slot:default="{ model: proxyModel, actions }">
          <v-card
            class="mx-auto"
            max-width="600"
            :title="`Cambiar valor de ${data.nombre}`"
          >
            <template v-slot:text>
              <v-form>
                <vjsf v-model="data" :schema="schema" :options="options"/>
              </v-form>
            </template>

            <template v-slot:actions>
              <v-spacer></v-spacer>
              <v-btn @click="cancelarActualizarValor" color="secondary" variant="tonal">
                Cancelar
              </v-btn>
              <v-btn @click="cambiarValorConfiguracion" :loading="estaGuandadoConfiguracion" color="error" variant="tonal">
                Actualizar
              </v-btn>
            </template>
          </v-card>
        </template>
      </v-confirm-edit>
    </v-dialog>
  </v-app>
</template>

<script setup>
  import Vjsf from '@koumoul/vjsf'
  import {ref, computed, watch} from 'vue'

  const configuraciones = ref([])
  const totalConfiguraciones = ref(0)
  const obteniendoConfiguraciones = ref(true)
  const filtros = ref([])
  const configuracionesPorPagina = ref(10)
  const paginaSeleccionada = ref(1)
  const storageUrl = import.meta.env.VITE_STORAGE_BASE_URL;
  const encabezados = [
    {
      title: 'Variable',
      align: 'start',
      sortable: false,
      key: 'identificador',
    },
    {
      title: 'Nombre común',
      align: 'start',
      sortable: false,
      key: 'nombre',
    },
    {
      title: 'Descripción',
      align: 'start',
      sortable: false,
      key: 'descripcion',
    },
    {
      title: 'Valor',
      align: 'start',
      sortable: false,
      key: 'valor',
    },
    {
      title: 'Etiquetas',
      align: 'start',
      sortable: false,
      key: 'tags',
    },
    {
      title: 'Actualizado el',
      align: 'start',
      sortable: false,
      key: 'updated_at',
    },
    {
      title: 'Acciones',
      align: 'center',
      sortable: false,
      key: 'actions'
    },
  ]

  const configuracionBusqueda = ref({ buscar: '', campo: null})
  async function obtenerConfiguracionesDesdeServer({itemsPerPage, page}){
    let parametros = filtros.value.map( f => `${f.campo.toLowerCase().replace('ó','o')}=${f.buscar}` ).join('&')
    console.log('filtros:', parametros)
    obteniendoConfiguraciones.value = true
    let data = await fetch(`/api/configuraciones?page=${page}&itemPerPage=${itemsPerPage}&${parametros}`,{
      method: 'GET',
      mode: 'cors',
    }).then( r => r.json() )
    configuraciones.value = data.data
    totalConfiguraciones.value = data.total
    obteniendoConfiguraciones.value = false
  }

  function buscarEnConfiguraciones(){
    let filtro = JSON.stringify(configuracionBusqueda.value)
    filtros.value.push(JSON.parse(filtro))
    configuracionBusqueda.value = { buscar: '', campo: null}
  }

  function eliminarFiltro(index){
    filtros.value.splice(index, 1)
  }

  watch(
    () => filtros.value.length,
    () => {
      obtenerConfiguracionesDesdeServer({
        itemsPerPage: configuracionesPorPagina.value,
        page: 1
      })
    }
  )

  const mostrarFormulario = ref(false)

  const plantillas = {
    'texto': `{
      "type": "string",
      "title": "Valor*",
      "layout": "text-field"\n}`,
    'textarea': `{
      "type": "string",
      "title": "Valor*",
      "layout": "textarea"\n}`,
    'numeric-input': `{
      "type": "integer",
      "title": "Valor*",
      "layout": "text-field"\n}`,
    'imagen': `{
      "type": "object",
      "title": "Valor*",
      "layout": {
        "comp": "file-input",
        "accept": "image/*"
      }\n}`,
    'selector-color': `{
      "type": "object",
      "properties": {
        "valor": {
          "type": "string",
          "title": "Color",
          "layout": "color-picker"
        }
      }\n}`,
    'archivo': `{
      "type": "object",
      "title": "Valor*",
      "layout": "file-input"\n}`,
    'rango': `{
      "type": "integer",
      "title": "Valor*",
      "minimum": 0,
      "maximum": 100,
      "layout": "slider"\n}`,
    'select-one': `{
      "type": "string",
      "title": "Valor*",
      "layout": "select",
      "enum": [
        "opción 1",
        "opción 2",
        "opción 3",
        "opción 4",
        "opción 5",
        "opción 6",
        "opción 7",
        "opción 8",
        "opción 9",
        "opción 10"
      ]\n}`,
    'select': `{
      "type": "array",
      "title": "Valor*",
      "layout": "select",
      "items": {
        "type": "string",
        "oneOf": [
          {
            "const": "value1",
            "title": "Value 1"
          },
          {
            "const": "value2",
            "title": "Value 2"
          }
        ]
      }\n}`,
  }
  const data = ref({
    nombre: '',
    descripcion: '',
    opciones: '{}',
    tipo: null
  })

  function setBaseLayout() {
      data.value.opciones = plantillas[data.value.tipo]
  }

  const schema = computed({
    get: () => {
      return {
        "type": "object",
        "properties": {
          "valor": JSON.parse(data.value.opciones)
        }
      }
    },
    /*set: (value) => {
      data.value.opciones = value
    }*/
  })

  const options = {
    "context": {},
    "width": 1134,
    "readOnly": false,
    "summary": false,
    "density": "default",
    "titleDepth": 2,
    "validateOn": "input",
    "initialValidation": "withData",
    "updateOn": "input",
    "debounceInputMs": 300,
    "defaultOn": "empty",
    "removeAdditional": "error",
    "autofocus": false,
    "readOnlyPropertiesMode": "show",
    "pluginsOptions": {},
    "locale": "es",
    "z-index" : 99000,
    "messages": {
      "errorOneOf": "Selecciona uno ...",
      "errorRequired": "información requerida",
      "addItem": "Agregar elemento",
      "delete": "Eliminar",
      "edit": "Editar",
      "close": "Cerrar",
      "duplicate": "Duplicar",
      "sort": "Ordenar",
      "up": "Mover arriba",
      "down": "Mover abajo",
      "showHelp": "Mostrar mensaje de ayuda",
      "mdeLink1": "[texto del link",
      "mdeLink2": "](link url)",
      "mdeImg1": "![](",
      "mdeImg2": "imagen url)",
    }
  }
  const articulos = ['los','las','una','unos','unas','de','el','la','lo','un','del','al']
  watch(
    () => data.value.nombre,
    (value) => {
      if(!value) return
      let sinAsentos = value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/ñ/gi,'n')
      let sinArticulos = sinAsentos.split(' ').filter(palabra => !articulos.includes(palabra))
      let sinEspacios = sinArticulos.join('_')
      data.value.identificador = sinEspacios.toUpperCase()
    }
  )

  const mostrarExito = ref(false)
  const mostrarAlerta = ref(false)
  const mensajeDeError = ref('')
  const estaGuandadoConfiguracion = ref(false)

  function getFormData(isUpdate=false){
    let formData = new FormData()
    for (const [key, value] of Object.entries(data.value) ) {
      if(data.value.tipo === 'selector-color' && key === 'valor'){
        formData.append(key, value.valor)
      }else{
        formData.append(key, value)
      }
    }
    if(isUpdate)
      formData.append('_method', 'PUT')
    return formData
  }
  async function guardarConfiguracion(){
    estaGuandadoConfiguracion.value = true

    await fetch('/api/configuraciones',{
      method: 'POST',
      mode: 'cors',
      body: getFormData(),
      headers: {
        'Accept' : 'application/json',
        //'Content-Type': 'application/json'
      },
    }).then( async r => {
      return {
        status: r.status,
        statusText: r.statusText,
        data: await r.json()
      }
    }).catch( e => console.log(e) )
      .finally(()=>{ estaGuandadoConfiguracion.value = false })
      .then((response) => {
        if(response.status < 200 || response.status >= 300){
          mostrarAlerta.value = true
          if(response.status === 422)
            mensajeDeError.value = response.data.message
          else
            mensajeDeError.value = response.statusText
        }
        if(response.status === 201){
          obtenerConfiguracionesDesdeServer({
            itemsPerPage: configuracionesPorPagina.value,
            page: paginaSeleccionada.value
          })
          mostrarExito.value = true
          mostrarFormulario.value = false
          resetFormData()
        }
      })
  }

  // Reinicia los valores del modelo de datos asociado a la forma
  function resetFormData() {
    data.value = {
      nombre: '',
      descripcion: '',
      opciones: '{}',
      tipo: null
    };
  }

  // Cuando se cierra la modal por oprimir fuera del área de la modal se reinician los valores de la forma.
  function onModalClosed() {
    resetFormData();
  }

  // Cuando se cancela el formulario de configuración se reinician los valores de la forma
  function cancelarFormularioConfiguracion(){
    mostrarFormulario.value = false;
    resetFormData();
  }

  // Cuando se cancela la actualización del valor se reinician los valores de la forma
  function cancelarActualizarValor(){
    actualizarValor.value = false
    resetFormData()
  }

  async function editarConfiguracion(item){
    let itemJson = JSON.parse(JSON.stringify(item));
    if(itemJson.tipo ==='selector-color'){
      itemJson.valor = {'valor': itemJson.valor};
    }
    data.value = itemJson;
    mostrarFormulario.value = true
  }
  async function actualizarConfiguracion(){
    estaGuandadoConfiguracion.value = true
    //let dataToSend = { ...data.value , valor: JSON.stringify(data.value.valor)}
    await fetch(`/api/configuraciones/${data.value.id}`,{
      method: 'POST',
      mode: 'cors',
      body: getFormData(true),
      headers: {
        'Accept' : 'application/json',
        //'Content-Type': 'multipart/form-data',
      },
    }).then( async r => {
      return {
        status: r.status,
        statusText: r.statusText,
        data: await r.json()
      }
    }).catch( e => console.log(e) )
      .finally(()=>{ estaGuandadoConfiguracion.value = false })
      .then((response) => {
        console.log(response)
        if(response.status < 200 || response.status >= 300){
          mostrarAlerta.value = true
          if(response.status === 422)
            mensajeDeError.value = response.data.message
          else
            mensajeDeError.value = response.statusText
          return
        }
        if (response.status === 200){
          obtenerConfiguracionesDesdeServer({
            itemsPerPage: configuracionesPorPagina.value,
            page: paginaSeleccionada.value
          })
          mostrarExito.value = true
          mostrarFormulario.value = false
          resetFormData()
        }
      })
  }

  const confirmacionEliminar = ref(false)
  const seEstaEliminando = ref(false)
  function dispararEliminarConfiguracion(item){
    confirmacionEliminar.value = true
    data.value = JSON.parse(JSON.stringify(item))
  }
  async function eliminarConfiguracion(){
    seEstaEliminando.value = true

    await fetch(`/api/configuraciones/${data.value.id}`,{
      method: 'DELETE',
      mode: 'cors',
      headers: {
        'Accept' : 'application/json',
      },
    })
    .then( async r => {
       if (r.status) mostrarExito.value = true
      confirmacionEliminar.value = false
    })
    .catch( e => console.log(e) )
    .finally(()=>{
      seEstaEliminando.value = false
      resetFormData()
      obtenerConfiguracionesDesdeServer({
        itemsPerPage: configuracionesPorPagina.value,
        page: paginaSeleccionada.value
      })
    })
  }
  function cancelarEliminacion(){
    resetFormData()
    confirmacionEliminar.value = false
  }

  const actualizarValor = ref(false)
  function dispararActualizarValor(item){
    let itemJson = JSON.parse(JSON.stringify(item));
    if (itemJson.tipo === 'selector-color') {
      itemJson.valor = {'valor': itemJson.valor};
    }
    data.value = itemJson;
    actualizarValor.value = true
  }
  async function cambiarValorConfiguracion(){
    estaGuandadoConfiguracion.value = true
    let form = new FormData()
    form.append('valor', data.value.tipo === 'selector-color' ? data.value.valor.valor : data.value.valor);
    form.append('_method', 'PUT')
    await fetch(`/api/configuraciones/${data.value.id}/valor`,{
      method: 'POST',
      mode: 'cors',
      body: form,
      headers: {
        'Accept' : 'application/json',
      },
    }).then( async r => {
      return {
        status: r.status,
        statusText: r.statusText,
        data: await r.json()
      }
    }).catch( e => console.log(e) )
      .finally(()=>{ estaGuandadoConfiguracion.value = false; resetFormData(); })
      .then((response) => {
        if(response.status < 200 || response.status >= 300){
          mostrarAlerta.value = true
          if(response.status === 422)
            mensajeDeError.value = response.data.message
          else
            mensajeDeError.value = response.statusText
          return
        }
        if (response.status === 200){
          obtenerConfiguracionesDesdeServer({
            itemsPerPage: configuracionesPorPagina.value,
            page: paginaSeleccionada.value
          })
          mostrarExito.value = true
          actualizarValor.value = false
        }
      })
  }

  const buildStorageUrl = (path) => {
    return `${storageUrl}/${path}`;
  };

</script>
