<template>
  <q-table
    v-model:fullscreen="fullscreen"
    flat
    row-key="id"
    :pagination="{ rowsPerPage }"
    :pagination-label="getPaginationLabel"
    :rows-per-page-label="$t('common.ui.table.rows_per_page')"
    :grid="$q.screen.lt.sm"
    :visible-columns
    :filter
    :columns
    :loading
    :rows
    class="softpar-table q-pa-sm q-mt-md"
    @row-click="onRowClick"
  >
    <template #top>
      <div
        class="flex full-width align-center q-mb-md q-pl-sm"
        style="gap: 1rem"
      >
        <div v-if="title" class="column text-h6">
          <span>{{ title }}</span>
          <span class="text-body2">{{
            `${rows.length} ${description} ${female ? "cadastradas" : "cadastrados"}`
          }}</span>
        </div>

        <slot name="top" :rows="rows" />

        <q-space />

        <q-btn
          v-if="addItem"
          color="primary"
          :style="addItemLabel ? '' : 'width: 40px; height: 40px'"
          :icon="addItemLabel ? undefined : 'mdi-plus'"
          :label="addItemLabel || undefined"
          :outline="outlineAdd"
          unelevated
          @click="onAddItem"
        />
      </div>

      <div class="flex full-width align-center q-mb-md" style="gap: 1rem">
        <DefaultInput
          v-if="showSearchField"
          v-model="filter"
          debounce="250"
          label="Busque por Unidade, status ou Responsavel"
          label-color="dark"
          :placeholder="$t('common.actions.search')"
          clearable
          class="q-mt-sm full-width search-input"
          color="dark"
          bg-color="transparent"
          dense
          input-class="q-pl-xs"
        >
          <template #prepend>
            <q-icon name="mdi-magnify" color="grey-6" />
          </template>
        </DefaultInput>
        <DefaultSelect
          v-if="showColumnsSelect"
          v-model="visibleColumns"
          multiple
          options-outlined
          :display-value="$q.lang.table.columns"
          emit-value
          map-options
          :options="mapColumns"
          style="width: 150px"
          options-selected-class="text-bold"
        />
      </div>
    </template>

    <template #body-cell-actions="{ row }">
      <q-td auto-width>
        <q-item-section class="no-wrap" style="flex-direction: row; gap: 4px">
          <slot name="body-cell-actions" :row="row" />
          <q-btn
            v-if="openItemRoute"
            outline
            icon="mdi-pencil-outline"
            style="width: 36px"
            @click.prevent.stop="
              router.push({ name: openItemRoute, params: { id: row.id } })
            "
          />
          <q-btn
            v-if="deleteFunction"
            outline
            icon="mdi-trash-can-outline"
            style="width: 36px"
            color="negative"
            @click.prevent.stop="onDelete(row.id)"
          />
        </q-item-section>
      </q-td>
    </template>

    <template #item="{ cols, row, index }">
      <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3">
        <q-card
          bordered
          flat
          class="q-pa-sm"
          @click="onRowClick($event, row, index)"
        >
          <q-list dense>
            <q-item
              v-for="col in cols.filter((col) => col.name !== 'desc')"
              :key="col.name"
            >
              <template v-if="col.name !== 'actions'">
                <q-item-section>
                  <q-item-label caption>{{ col.label }}</q-item-label>
                  <q-item-label>{{ col.value }}</q-item-label>
                </q-item-section>
              </template>
              <template v-else>
                <slot name="body-cell-actions" :row="row" />
                <q-item-section
                  v-if="openItemRoute || deleteFunction"
                  style="flex-direction: row; gap: 4px"
                >
                  <q-btn
                    v-if="openItemRoute"
                    outline
                    icon="mdi-pencil-outline"
                    style="width: 36px"
                    @click.prevent.stop="
                      router.push({
                        name: openItemRoute,
                        params: { id: row.id },
                      })
                    "
                  />
                  <q-btn
                    v-if="deleteFunction"
                    outline
                    icon="mdi-trash-can-outline"
                    style="width: 36px"
                    color="negative"
                    @click.prevent.stop="onDelete(row.id)"
                  />
                </q-item-section>
              </template>
            </q-item>
          </q-list>
        </q-card>
      </div>
    </template>

    <template #loading>
      <q-inner-loading showing color="primary" />
    </template>

    <template v-if="!hideNoDataLabel" #no-data>
      <div v-if="!loading" class="q-my-md row justify-center full-width">
        <div class="q-pa-md body2">
          {{ $t("http.errors.no_records_found") }}
        </div>
      </div>
    </template>
    <template v-for="slotName in usableSlots($slots)" #[slotName]="data">
      <slot :name="slotName" v-bind="data" />
    </template>
  </q-table>
</template>

<script setup>
import { ref, onMounted, toRaw, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { useQuasar } from "quasar";

import DefaultInput from "./DefaultInput.vue";
import DefaultSelect from "./DefaultSelect.vue";

const emit = defineEmits(["onRowClick", "onAddItem", "noRows"]);

const {
  columns,
  apiCall,
  outlineAdd,
  openItem,
  openItemRoute,
  addItem,
  addItemLabel,
  addItemRoute,
  rowsPerPage,
  showSearchField,
  noApiCall,
  hideNoDataLabel,
  deleteFunction,
} = defineProps({
  title: {
    type: String,
    default: null,
  },
  columns: {
    type: Array,
    required: true,
  },
  apiCall: {
    type: Function,
    default: null,
  },
  description: {
    type: String,
    default: "linhas",
  },
  female: {
    type: Boolean,
    default: true,
  },
  outlineAdd: {
    type: Boolean,
    default: false,
  },
  openItem: {
    type: Boolean,
    default: false,
  },
  openItemRoute: {
    type: String,
    default: "",
  },
  addItem: {
    type: Boolean,
    default: false,
  },
  addItemLabel: {
    type: String,
    default: "",
  },
  addItemRoute: {
    type: String,
    default: "",
  },
  rowsPerPage: {
    type: Number,
    default: 10,
  },
  showSearchField: {
    type: Boolean,
    default: true,
  },
  showColumnsSelect: {
    type: Boolean,
    default: false,
  },
  noApiCall: {
    type: Boolean,
    default: false,
  },
  hideNoDataLabel: {
    type: Boolean,
    default: false,
  },
  deleteFunction: {
    type: Function,
    default: null,
  },
});

const router = useRouter();
const { t } = useI18n();
const $q = useQuasar();

const rows = defineModel("rows", { type: Array, default: [] });
const filter = ref("");
const loading = ref(true);
const fullscreen = ref(false);

const mapColumns = columns.reduce((accm, column) => {
  if (!column.required) {
    accm.push({
      label: column.label,
      value: column.name,
    });
  }
  return accm;
}, []);

const visibleColumns = ref(mapColumns.map((column) => column.value));

const getPaginationLabel = (from, to, last) => {
  return `${from}-${to} ${t("common.ui.table.of")} ${last}`;
};

const onRowClick = (evt, row, index) => {
  const item = toRaw(row);
  if (openItem) {
    if (openItemRoute) {
      router.push({ name: openItemRoute, params: { id: item.id } });
    } else {
      emit("onRowClick", { evt, row, index });
    }
  }
};

const onAddItem = () => {
  if (addItem) {
    if (addItemRoute) {
      router.push({ name: addItemRoute });
    } else {
      emit("onAddItem");
    }
  }
};

const onDelete = async (id) => {
  if (deleteFunction) {
    $q.dialog({
      title: t("common.ui.messages.confirm_action"),
      message: t("common.ui.messages.are_you_sure_delete"),
      ok: {
        color: "negative",
        label: t("common.actions.delete"),
      },
      cancel: {
        color: "primary",
        outline: true,
        label: t("common.actions.cancel"),
      },
    }).onOk(async () => {
      loading.value = true;
      try {
        await deleteFunction(id);
        await onRequest();
      } catch (error) {
        console.error(error);
      } finally {
        loading.value = false;
      }
    });
  }
};

const onRequest = async () => {
  if (noApiCall) {
    loading.value = false;
    return;
  }
  loading.value = true;

  const response = await apiCall();
  rows.value = response;

  if (rows.value.length == 0) {
    emit("noRows");
  }
  loading.value = false;
};

const usableSlots = (slots) => {
  const availableSlots = Object.keys(slots);
  const usableSlots = availableSlots.filter(
    (slot) =>
      !["body-cell-actions", "top", "loading", "no-data"].includes(slot),
  );
  return usableSlots;
};

watch(
  () => apiCall,
  async () => {
    await onRequest();
  },
);

onMounted(async () => {
  await onRequest({
    filter: undefined,
  });
});

defineExpose({
  refresh: onRequest,
});
</script>

<style lang="scss">
@import "src/css/table.scss";
</style>
