<template>
  <div v-if="aberto" class="eli-tabela-modal-colunas__overlay" role="presentation" @click.self="emitFechar">
    <div
      class="eli-tabela-modal-colunas__modal"
      role="dialog"
      aria-modal="true"
      aria-label="Configurar colunas"
    >
      <header class="eli-tabela-modal-colunas__header">
        <h3 class="eli-tabela-modal-colunas__titulo">Colunas</h3>
        <button type="button" class="eli-tabela-modal-colunas__fechar" aria-label="Fechar" @click="emitFechar">
          ×
        </button>
      </header>

      <div class="eli-tabela-modal-colunas__conteudo">
        <div class="eli-tabela-modal-colunas__coluna">
          <div class="eli-tabela-modal-colunas__coluna-titulo">Visíveis</div>
          <div
            class="eli-tabela-modal-colunas__lista"
            @dragover.prevent
            @drop="(e) => onDropLista(e, 'visiveis', null)"
          >
            <div
              v-for="(rotulo, idx) in visiveisLocal"
              :key="`vis-${rotulo}`"
              class="eli-tabela-modal-colunas__item"
              draggable="true"
              @dragstart="(e) => onDragStart(e, rotulo, 'visiveis', idx)"
              @dragover.prevent
              @drop="(e) => onDropItem(e, 'visiveis', idx)"
            >
              <span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
              <span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
            </div>
          </div>
        </div>

        <div class="eli-tabela-modal-colunas__coluna">
          <div class="eli-tabela-modal-colunas__coluna-titulo">Invisíveis</div>
          <div
            class="eli-tabela-modal-colunas__lista"
            @dragover.prevent
            @drop="(e) => onDropLista(e, 'invisiveis', null)"
          >
            <div
              v-for="(rotulo, idx) in invisiveisLocal"
              :key="`inv-${rotulo}`"
              class="eli-tabela-modal-colunas__item"
              draggable="true"
              @dragstart="(e) => onDragStart(e, rotulo, 'invisiveis', idx)"
              @dragover.prevent
              @drop="(e) => onDropItem(e, 'invisiveis', idx)"
            >
              <span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
              <span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
            </div>
          </div>
        </div>
      </div>

      <footer class="eli-tabela-modal-colunas__footer">
        <button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--sec" @click="emitFechar">
          Cancelar
        </button>
        <button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--prim" @click="emitSalvar">
          Salvar
        </button>
      </footer>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, ref, watch } from "vue";
import type { EliTabelaColunasConfig } from "./colunasStorage";
import type { EliColuna } from "./types-eli-tabela";

type OrigemLista = "visiveis" | "invisiveis";

type DragPayload = {
  rotulo: string;
  origem: OrigemLista;
  index: number;
};

const DRAG_MIME = "application/x-eli-tabela-coluna";

export default defineComponent({
  name: "EliTabelaModalColunas",
  props: {
    aberto: {
      type: Boolean,
      required: true,
    },
    rotulosColunas: {
      type: Array as PropType<string[]>,
      required: true,
    },
    configInicial: {
      type: Object as PropType<EliTabelaColunasConfig>,
      required: true,
    },
    colunas: {
      type: Array as PropType<Array<EliColuna<any>>>,
      required: true,
    },
  },
  emits: {
    fechar() {
      return true;
    },
    salvar(_config: EliTabelaColunasConfig) {
      return true;
    },
  },
  setup(props, { emit }) {
    const visiveisLocal = ref<string[]>([]);
    const invisiveisLocal = ref<string[]>([]);

    function sincronizarEstado() {
      const todos = props.rotulosColunas;
      const configTemDados =
        (props.configInicial.visiveis?.length ?? 0) > 0 ||
        (props.configInicial.invisiveis?.length ?? 0) > 0;

      const invisiveisPadraoSet = new Set(
        props.colunas.filter((c) => c.visivel === false).map((c) => c.rotulo)
      );

      const invisiveisSet = configTemDados
        ? new Set(props.configInicial.invisiveis ?? [])
        : invisiveisPadraoSet;

      const baseVisiveis = todos.filter((r) => !invisiveisSet.has(r));

      // ordenação: aplica ordem salva (visiveis) e adiciona novas ao final
      const ordemSalva = props.configInicial.visiveis ?? [];
      const setVis = new Set(baseVisiveis);
      const ordenadas: string[] = [];

      for (const r of ordemSalva) {
        if (setVis.has(r)) ordenadas.push(r);
      }
      for (const r of baseVisiveis) {
        if (!ordenadas.includes(r)) ordenadas.push(r);
      }

      visiveisLocal.value = ordenadas;

      // invisíveis: somente as que existem na tabela
      invisiveisLocal.value = todos.filter((r) => invisiveisSet.has(r));
    }

    watch(
      () => [props.aberto, props.rotulosColunas, props.configInicial, props.colunas] as const,
      () => {
        if (props.aberto) sincronizarEstado();
      },
      { deep: true, immediate: true }
    );

    function emitFechar() {
      emit("fechar");
    }

    function emitSalvar() {
      emit("salvar", {
        visiveis: [...visiveisLocal.value],
        invisiveis: [...invisiveisLocal.value],
      });
    }

    function writeDragData(e: DragEvent, payload: DragPayload) {
      try {
        e.dataTransfer?.setData(DRAG_MIME, JSON.stringify(payload));
        e.dataTransfer?.setData("text/plain", payload.rotulo);
        e.dataTransfer!.effectAllowed = "move";
      } catch {
        // ignore
      }
    }

    function readDragData(e: DragEvent): DragPayload | null {
      try {
        const raw = e.dataTransfer?.getData(DRAG_MIME);
        if (!raw) return null;
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed.rotulo !== "string" || (parsed.origem !== "visiveis" && parsed.origem !== "invisiveis")) {
          return null;
        }
        return parsed as DragPayload;
      } catch {
        return null;
      }
    }

    function removerDaOrigem(payload: DragPayload) {
      const origemArr = payload.origem === "visiveis" ? visiveisLocal.value : invisiveisLocal.value;
      const idx = origemArr.indexOf(payload.rotulo);
      if (idx >= 0) origemArr.splice(idx, 1);
    }

    function inserirNoDestino(destino: OrigemLista, rotulo: string, index: number | null) {
      const arr = destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value;
      // remove duplicatas
      const existing = arr.indexOf(rotulo);
      if (existing >= 0) arr.splice(existing, 1);

      if (index === null || index < 0 || index > arr.length) {
        arr.push(rotulo);
      } else {
        arr.splice(index, 0, rotulo);
      }
    }

    function onDragStart(e: DragEvent, rotulo: string, origem: OrigemLista, index: number) {
      writeDragData(e, { rotulo, origem, index });
    }

    function onDropItem(e: DragEvent, destino: OrigemLista, index: number) {
      const payload = readDragData(e);
      if (!payload) return;

      // remove da origem e insere no destino na posição do item
      removerDaOrigem(payload);
      inserirNoDestino(destino, payload.rotulo, index);

      // garante que uma coluna não fique nos 2 lados
      if (destino === "visiveis") {
        const idxInv = invisiveisLocal.value.indexOf(payload.rotulo);
        if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1);
      } else {
        const idxVis = visiveisLocal.value.indexOf(payload.rotulo);
        if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1);
      }
    }

    function onDropLista(e: DragEvent, destino: OrigemLista, _index: number | null) {
      const payload = readDragData(e);
      if (!payload) return;

      removerDaOrigem(payload);
      inserirNoDestino(destino, payload.rotulo, null);

      if (destino === "visiveis") {
        const idxInv = invisiveisLocal.value.indexOf(payload.rotulo);
        if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1);
      } else {
        const idxVis = visiveisLocal.value.indexOf(payload.rotulo);
        if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1);
      }
    }

    return {
      visiveisLocal,
      invisiveisLocal,
      emitFechar,
      emitSalvar,
      onDragStart,
      onDropItem,
      onDropLista,
    };
  },
});
</script>

<style scoped>
.eli-tabela-modal-colunas__overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.35);
  z-index: 4000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.eli-tabela-modal-colunas__modal {
  width: min(860px, 100%);
  background: #fff;
  border-radius: 14px;
  border: 1px solid rgba(15, 23, 42, 0.1);
  box-shadow: 0 18px 60px rgba(15, 23, 42, 0.25);
  overflow: hidden;
}

.eli-tabela-modal-colunas__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(15, 23, 42, 0.08);
}

.eli-tabela-modal-colunas__titulo {
  font-size: 1rem;
  margin: 0;
}

.eli-tabela-modal-colunas__fechar {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  color: rgba(15, 23, 42, 0.8);
}

.eli-tabela-modal-colunas__fechar:hover,
.eli-tabela-modal-colunas__fechar:focus-visible {
  background: rgba(15, 23, 42, 0.06);
}

.eli-tabela-modal-colunas__conteudo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  padding: 16px;
}

.eli-tabela-modal-colunas__coluna-titulo {
  font-weight: 600;
  margin-bottom: 8px;
}

.eli-tabela-modal-colunas__lista {
  min-height: 260px;
  border: 1px solid rgba(15, 23, 42, 0.12);
  border-radius: 12px;
  padding: 10px;
  background: rgba(15, 23, 42, 0.01);
}

.eli-tabela-modal-colunas__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 10px;
  border-radius: 10px;
  border: 1px solid rgba(15, 23, 42, 0.08);
  background: #fff;
  cursor: grab;
  user-select: none;
}

.eli-tabela-modal-colunas__item + .eli-tabela-modal-colunas__item {
  margin-top: 8px;
}

.eli-tabela-modal-colunas__item:active {
  cursor: grabbing;
}

.eli-tabela-modal-colunas__item-handle {
  color: rgba(15, 23, 42, 0.55);
  font-size: 14px;
}

.eli-tabela-modal-colunas__item-texto {
  flex: 1;
  min-width: 0;
}

.eli-tabela-modal-colunas__footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 16px;
  border-top: 1px solid rgba(15, 23, 42, 0.08);
}

.eli-tabela-modal-colunas__botao {
  height: 34px;
  padding: 0 14px;
  border-radius: 10px;
  border: 1px solid rgba(15, 23, 42, 0.12);
  background: #fff;
  cursor: pointer;
  font-size: 0.9rem;
}

.eli-tabela-modal-colunas__botao--sec:hover,
.eli-tabela-modal-colunas__botao--sec:focus-visible {
  background: rgba(15, 23, 42, 0.06);
}

.eli-tabela-modal-colunas__botao--prim {
  border: none;
  background: rgba(37, 99, 235, 0.95);
  color: #fff;
}

.eli-tabela-modal-colunas__botao--prim:hover,
.eli-tabela-modal-colunas__botao--prim:focus-visible {
  background: rgba(37, 99, 235, 1);
}

@media (max-width: 720px) {
  .eli-tabela-modal-colunas__conteudo {
    grid-template-columns: 1fr;
  }
}
</style>
