<template>
  <nav
    v-if="totalPaginasExibidas > 1"
    class="eli-tabela__paginacao"
    role="navigation"
    aria-label="Paginação de resultados"
  >
    <button
      type="button"
      class="eli-tabela__pagina-botao"
      :disabled="anteriorDesabilitado"
      aria-label="Página anterior"
      @click="irParaPagina(paginaAtual - 1)"
    >
      <<
    </button>

    <template v-for="(item, index) in botoes" :key="`${item.label}-${index}`">
      <span
        v-if="item.ehEllipsis"
        class="eli-tabela__pagina-ellipsis"
        aria-hidden="true"
      >
        {{ item.label }}
      </span>
      <button
        v-else
        type="button"
        class="eli-tabela__pagina-botao"
        :class="item.ativo ? 'eli-tabela__pagina-botao--ativo' : undefined"
        :disabled="item.ativo"
        :aria-current="item.ativo ? 'page' : undefined"
        :aria-label="`Ir para página ${item.label}`"
        @click="irParaPagina(item.pagina)"
      >
        {{ item.label }}
      </button>
    </template>

    <button
      type="button"
      class="eli-tabela__pagina-botao"
      :disabled="proximaDesabilitada"
      aria-label="Próxima página"
      @click="irParaPagina(paginaAtual + 1)"
    >
      >>
    </button>
  </nav>
</template>

<script lang="ts">
import { computed, defineComponent } from "vue";

export default defineComponent({
  name: "EliTabelaPaginacao",
  props: {
    pagina: {
      type: Number,
      required: true,
    },
    totalPaginas: {
      type: Number,
      required: true,
    },
    maximoBotoes: {
      type: Number,
      required: false,
    },
  },
  emits: {
    alterar(pagina: number) {
      return Number.isFinite(pagina);
    },
  },
  setup(props, { emit }) {
    /**
     * Define o limite de botões visíveis. Mantemos um mínimo de 7 para garantir
     * uma navegação confortável, mesmo quando o consumidor não informa o valor.
     */
    const maximoBotoesVisiveis = computed(() => {
      const valor = props.maximoBotoes;
      if (typeof valor === "number" && valor >= 5) {
        return Math.floor(valor);
      }
      return 7;
    });

    /**
     * Constrói a lista de botões/reticências que serão exibidos na paginação.
     * Mantemos sempre a primeira e a última página visíveis, posicionando as
     * demais de forma dinâmica ao redor da página atual.
     */
    const botoes = computed(() => {
      const total = props.totalPaginas;
      const atual = props.pagina;
      const limite = maximoBotoesVisiveis.value;
      const resultado: Array<{
        label: string;
        pagina?: number;
        ativo?: boolean;
        ehEllipsis?: boolean;
      }> = [];

      const adicionarPagina = (pagina: number) => {
        resultado.push({
          label: String(pagina),
          pagina,
          ativo: pagina === atual,
        });
      };

      const adicionarReticencias = () => {
        resultado.push({ label: "…", ehEllipsis: true });
      };

      if (total <= limite) {
        for (let pagina = 1; pagina <= total; pagina += 1) {
          adicionarPagina(pagina);
        }
        return resultado;
      }

      const visiveisCentrais = Math.max(3, limite - 2);
      let inicio = Math.max(2, atual - Math.floor(visiveisCentrais / 2));
      let fim = inicio + visiveisCentrais - 1;

      if (fim >= total) {
        fim = total - 1;
        inicio = fim - visiveisCentrais + 1;
      }

      adicionarPagina(1);

      if (inicio > 2) {
        adicionarReticencias();
      }

      for (let pagina = inicio; pagina <= fim; pagina += 1) {
        adicionarPagina(pagina);
      }

      if (fim < total - 1) {
        adicionarReticencias();
      }

      adicionarPagina(total);

      return resultado;
    });

    /**
     * Emite a requisição de mudança de página garantindo que o valor esteja
     * dentro dos limites válidos informados pelo componente pai.
     */
    function irParaPagina(pagina: number | undefined) {
      if (!pagina) {
        return;
      }
      const alvo = Math.min(Math.max(1, pagina), props.totalPaginas);
      if (alvo !== props.pagina) {
        emit("alterar", alvo);
      }
    }

    const anteriorDesabilitado = computed(() => props.pagina <= 1);
    const proximaDesabilitada = computed(() => props.pagina >= props.totalPaginas);
    const paginaAtual = computed(() => props.pagina);
    const totalPaginasExibidas = computed(() => props.totalPaginas);

    return {
      botoes,
      irParaPagina,
      anteriorDesabilitado,
      proximaDesabilitada,
      paginaAtual,
      totalPaginasExibidas,
    };
  },
});
</script>

<style>
.eli-tabela__paginacao {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 12px;
  flex-wrap: wrap;
}

.eli-tabela__pagina-botao {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 9999px;
  border: 1px solid rgba(15, 23, 42, 0.12);
  background: #ffffff;
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(15, 23, 42, 0.82);
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease,
    color 0.2s ease;
}

.eli-tabela__pagina-botao:hover,
.eli-tabela__pagina-botao:focus-visible {
  background-color: rgba(37, 99, 235, 0.08);
  border-color: rgba(37, 99, 235, 0.4);
  color: rgba(37, 99, 235, 0.95);
}

.eli-tabela__pagina-botao:focus-visible {
  outline: 2px solid rgba(37, 99, 235, 0.45);
  outline-offset: 2px;
}

.eli-tabela__pagina-botao:disabled {
  cursor: default;
  opacity: 0.5;
  background: rgba(148, 163, 184, 0.08);
  border-color: rgba(148, 163, 184, 0.18);
  color: rgba(71, 85, 105, 0.75);
}

.eli-tabela__pagina-botao--ativo {
  background: rgba(37, 99, 235, 0.12);
  border-color: rgba(37, 99, 235, 0.4);
  color: rgba(37, 99, 235, 0.95);
}

.eli-tabela__pagina-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  color: rgba(107, 114, 128, 0.85);
  font-size: 0.9rem;
}
</style>
