<script setup>
import BaseIndex from "../../components/base/BaseIndex.vue";
import B2CDataTable from "../../components/common/B2CDataTable.vue";

import { mergeDataTableColumns } from "../../composables/mergeDataTableColumns.js";
import {
  fetchDataTable,
  getDataTableColumns,
} from "../../services/dataTableService.js";
import { ensureCsrf } from "../../services/api";

import { computed, nextTick, onMounted, ref } from "vue";

/** Event filter (Drawer) — values match Spatie `event` column. */
const EVENT_SELECT_OPTIONS = [
  { label: "Created", value: "created" },
  { label: "Updated", value: "updated" },
  { label: "Deleted", value: "deleted" },
  { label: "Restored", value: "restored" },
];

const BADGE = {
  ok: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300",
  info: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300",
  muted:
    "bg-surface-200 text-surface-700 dark:bg-surface-600 dark:text-surface-200",
  danger:
    "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300",
};

const EVENT_VALUE_MAP = {
  created: { label: "Created", class: BADGE.ok },
  updated: { label: "Updated", class: BADGE.info },
  deleted: { label: "Deleted", class: BADGE.danger },
  restored: {
    label: "Restored",
    class:
      "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300",
  },
};

const RESOURCE_KEY = "activity-log";

/** @type {import('vue').Ref<Array<Record<string, unknown>>>} */
const apiColumnsRaw = ref([]);

const columns = computed(() =>
  mergeDataTableColumns(apiColumnsRaw.value, {
    created_at: {
      searchable: false,
      filterable: false,
      sortable: true,
    },
    event: {
      type: "badge",
      filterType: "select",
      filterOptions: EVENT_SELECT_OPTIONS,
      valueMap: EVENT_VALUE_MAP,
      defaultBadgeEntry: {
        label: "—",
        class: BADGE.muted,
      },
    },
    user_label: {
      filterKey: "user_label",
      searchable: false,
      sortable: false,
    },
    subject_line: {
      searchable: false,
      filterable: false,
      sortable: false,
    },
  }),
);

const rows = ref([]);
const totalRecords = ref(0);
const totalAllRecords = ref(0);

const loading = ref(false);
const error = ref("");

const pagination = ref({ page: 1, limit: 25 });
const sort = ref([{ field: "created_at", order: -1 }]);

const tableBackendState = ref({
  globalSearch: "",
  filters: {},
  visibleColumns: [],
  columnOrder: [],
});

const displayRows = computed(() => rows.value);

let loadTimer = null;
let fetchSeq = 0;

function criteriaSignature(g, filters) {
  return JSON.stringify({
    globalSearch: g,
    filters: filters ?? {},
  });
}

function scheduleLoad() {
  if (loadTimer) clearTimeout(loadTimer);
  loadTimer = setTimeout(() => {
    loadTimer = null;
    load();
  }, 400);
}

function defaultVisibleKeys() {
  return columns.value
    .filter((c) => c.defaultVisible !== false)
    .map((c) => c.key);
}

function effectiveVisibleColumns() {
  const v = tableBackendState.value.visibleColumns;
  if (Array.isArray(v) && v.length > 0) return [...v];

  return defaultVisibleKeys();
}

function sortFieldApi(field) {
  const allowed = new Set(["created_at", "description", "event", "id"]);
  return allowed.has(field) ? field : "created_at";
}

async function load() {
  const seq = ++fetchSeq;
  loading.value = true;
  error.value = "";
  try {
    await ensureCsrf();

    const s0 = sort.value?.[0];
    const sf = sortFieldApi(s0?.field ?? "created_at");
    const order = Number(s0?.order) === 1 ? 1 : -1;

    const payload = {
      pagination: { ...pagination.value },
      sort: [{ field: sf, order }],
      visibleColumns: effectiveVisibleColumns(),
      columnOrder:
        tableBackendState.value.columnOrder?.length > 0
          ? [...tableBackendState.value.columnOrder]
          : effectiveVisibleColumns(),
      filters: { ...(tableBackendState.value.filters ?? {}) },
      globalSearch: String(tableBackendState.value.globalSearch ?? "").trim(),
    };

    const data = await fetchDataTable(RESOURCE_KEY, payload);
    if (seq !== fetchSeq) return;

    rows.value = data.data ?? [];

    totalRecords.value = data.meta?.total ?? 0;
    totalAllRecords.value = data.meta?.totalAll ?? data.meta?.total ?? 0;
  } catch (e) {
    if (seq !== fetchSeq) return;

    error.value = e?.response?.data?.message ?? "Could not load activity log.";
    rows.value = [];
    totalRecords.value = 0;
    totalAllRecords.value = 0;
  } finally {
    if (seq === fetchSeq) loading.value = false;
  }
}

onMounted(async () => {
  await nextTick();
  await ensureCsrf();
  try {
    apiColumnsRaw.value = await getDataTableColumns(RESOURCE_KEY);
  } catch {
    apiColumnsRaw.value = [];
  }
  await load();
});

function onTableState(state) {
  const prevCriteria = criteriaSignature(
    tableBackendState.value.globalSearch,
    tableBackendState.value.filters,
  );
  const prevVis = JSON.stringify(tableBackendState.value.visibleColumns ?? []);
  const prevOrder = JSON.stringify(tableBackendState.value.columnOrder ?? []);

  const nextGs = String(state?.globalSearch ?? "");
  const nextFilters =
    state?.filters && typeof state.filters === "object"
      ? { ...state.filters }
      : {};
  const nextVisible = Array.isArray(state.visibleColumns)
    ? [...state.visibleColumns]
    : [];
  const nextOrder = Array.isArray(state.columnOrder)
    ? [...state.columnOrder]
    : [];

  tableBackendState.value = {
    globalSearch: nextGs,
    filters: nextFilters,
    visibleColumns: nextVisible,
    columnOrder: nextOrder,
  };

  const nextCriteria = criteriaSignature(nextGs, nextFilters);
  const nextVis = JSON.stringify(nextVisible);
  const nextOrderStr = JSON.stringify(nextOrder);

  if (nextCriteria !== prevCriteria) {
    pagination.value = { ...pagination.value, page: 1 };
    scheduleLoad();

    return;
  }

  if (nextVis !== prevVis || nextOrderStr !== prevOrder) {
    scheduleLoad();
  }
}

function formatWhen(iso) {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleString(undefined, {
      dateStyle: "medium",
      timeStyle: "short",
    });
  } catch {
    return iso;
  }
}
</script>

<template>
  <BaseIndex flush hide-header>
    <B2CDataTable
      table-key="settings.activity-log"
      :columns="columns"
      :rows="displayRows"
      :loading="loading"
      server-mode
      resource-key="activity-log"
      :enable-export="true"
      :total-records="totalRecords"
      :total-all-records="totalAllRecords"
      :pagination="pagination"
      :sort="sort"
      :persist-to-server="true"
      search-placeholder="Zoeken…"
      :table-error="error"
      :rows-per-page-options="[10, 25, 50]"
      :paginator="true"
      resource-label-singular="entry"
      resource-label-plural="entries"
      @update:pagination="
        pagination = $event;
        load();
      "
      @update:sort="
        sort = $event;
        load();
      "
      @update:state="onTableState($event)"
    >
      <template #toolbar-title>
        <div>
          <h1
            class="text-2xl font-semibold tracking-tight text-surface-950 dark:text-surface-0 m-0"
          >
            Activity log
          </h1>
          <p
            class="text-sm text-surface-600 dark:text-surface-400 mt-1.5 mb-0 max-w-3xl"
          >
            Spatie Activity Log audit trail.
          </p>
        </div>
      </template>
      <template #cell-created_at="{ row }">
        {{ formatWhen(row.created_at) }}
      </template>
      <template #cell-description="{ row }">
        <span class="line-clamp-2">{{ row.description }}</span>
      </template>
    </B2CDataTable>
  </BaseIndex>
</template>
