<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
    :rows
    :loading
    class="softpar-table q-pa-sm"
    @row-click="onRowClick"
  >
    <template #top>
      <div
        class="flex full-width justify-between align-center q-mb-md q-pl-sm"
        style="gap: 1rem"
      >
        <q-input
          v-if="showSearchField"
          v-model="filter"
          debounce="250"
          :placeholder="$t('common.actions.search')"
          clearable
          autofocus
          class=""
          color="primary"
        >
          <template #append>
            <q-icon name="mdi-magnify" />
          </template>
        </q-input>

        <q-select
          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"
        />

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

        <q-space />

        <q-btn
          v-if="addItem"
          color="primary"
          padding="10px 16px"
          :outline="outlineAdd"
          :label="$t('common.actions.add')"
          @click="onAddItem"
        >
        </q-btn>
      </div>
    </template>

    <template #body-cell-actions="{ row }">
      <q-td auto-width>
        <slot name="body-cell-actions" :row="row" />
        <q-item-section v-if="deleteFunction">
          <q-btn
            color="negative"
            flat
            dense
            icon="mdi-delete"
            style="width: 45px"
            class="q-ml-auto q-mr-sm"
            @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="deleteFunction">
                  <q-btn
                    color="negative"
                    flat
                    dense
                    icon="mdi-delete"
                    style="width: 45px"
                    class="q-ml-auto q-mr-sm"
                    @click.prevent.stop="onDelete(col.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="name in $slots" #[name]="data">
      <slot :name="name" v-bind="data"></slot>
    </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";

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

const {
  columns,
  apiCall,
  outlineAdd,
  openItem,
  openItemRoute,
  addItem,
  addItemRoute,
  rowsPerPage,
  showSearchField,
  noApiCall,
  hideNoDataLabel,
  deleteFunction,
} = defineProps({
  columns: {
    type: Array,
    required: true,
  },
  apiCall: {
    type: Function,
    required: true,
  },
  outlineAdd: {
    type: Boolean,
    default: false,
  },
  openItem: {
    type: Boolean,
    default: false,
  },
  openItemRoute: {
    type: String,
    default: "",
  },
  addItem: {
    type: Boolean,
    default: true,
  },
  addItemRoute: {
    type: String,
    default: "",
  },
  rowsPerPage: {
    type: Number,
    default: 10,
  },
  showSearchField: {
    type: Boolean,
    default: true,
  },
  showColumnsSelect: {
    type: Boolean,
    default: true,
  },
  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 = ref([]);
const filter = ref("");
const loading = ref(true);
const fullscreen = ref(false);

const getPaginationLabel = (from, to, last) => {
  return `${from}-${to} de ${last}`;
};

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

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 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",
        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.splice(0, rows.value.length, ...response);

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

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

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

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