import { ref } from "vue";
import { fetchDataTable } from "../services/dataTableService.js";

/**
 * Composable to load paginated/sorted/filtered DataTable data from POST /api/datatables/{resourceKey}.
 * Page remains owner: call fetch(payload) when table state changes. No API calls inside B2CDataTable.
 *
 * @param {string} resourceKey - e.g. 'companies', 'users', 'roles'
 * @param {object} [initialOptions] - optional default payload for refetch(); can be partial
 * @returns {{ rows: import('vue').Ref<any[]>, total: import('vue').Ref<number>, totalAll: import('vue').Ref<number>, loading: import('vue').Ref<boolean>, error: import('vue').Ref<string|null>, fetch: (payload: object) => Promise<void>, fetchPage: (payload: object) => Promise<{ data: any[], meta: { total: number, totalAll: number } }>, refetch: () => Promise<void> }}
 */
export function useDataTableData(resourceKey, initialOptions = null) {
  const rows = ref([]);
  const total = ref(0);
  const totalAll = ref(0);
  const loading = ref(false);
  const error = ref(null);

  /** Last payload passed to fetch(), used by refetch(). */
  let lastPayload = initialOptions ?? null;

  /** AbortController for the currently active request (fetch or fetchPage). */
  let currentController = null;

  function startRequest() {
    // Cancel any in-flight request before starting a new one
    if (currentController) {
      currentController.abort();
    }
    currentController = new AbortController();
    return currentController;
  }

  /**
   * Fetch data with the given payload. Handles 401 by setting error; no infinite retry.
   * @param {object} payload - { tableKey?, pagination: { page, limit }, sort?, visibleColumns?, filters?, globalSearch? }
   */
  async function fetch(payload) {
    lastPayload = payload;
    const controller = startRequest();
    loading.value = true;
    error.value = null;
    try {
      const res = await fetchDataTable(resourceKey, payload, {
        signal: controller.signal,
      });
      rows.value = res?.data ?? [];
      const meta = res?.meta ?? {};
      total.value = typeof meta.total === "number" ? meta.total : 0;
      totalAll.value = typeof meta.totalAll === "number" ? meta.totalAll : 0;
    } catch (err) {
      // Ignore abort errors from a superseded request
      if (err?.code === "ERR_CANCELED") {
        return;
      }
      const message =
        err?.response?.data?.message ??
        err?.message ??
        "Failed to load table data.";
      error.value = message;
      rows.value = [];
      total.value = 0;
      totalAll.value = 0;
    } finally {
      // Only clear loading if this is still the active request
      if (controller === currentController) {
        loading.value = false;
      }
    }
  }

  /**
   * Fetch a single page and return { data, meta } without mutating rows/total/totalAll.
   * For infinite scroll: parent manages rows and calls fetchPage, then appends or replaces.
   * Sets loading and error; updates lastPayload for refetch().
   *
   * @param {object} payload - same shape as fetch()
   * @returns {Promise<{ data: any[], meta: { total: number, totalAll: number } }>}
   */
  async function fetchPage(payload) {
    lastPayload = payload;
    const controller = startRequest();
    loading.value = true;
    error.value = null;
    try {
      const res = await fetchDataTable(resourceKey, payload, {
        signal: controller.signal,
      });
      const data = res?.data ?? [];
      const meta = res?.meta ?? {};
      return {
        data,
        meta: {
          total: typeof meta.total === "number" ? meta.total : 0,
          totalAll: typeof meta.totalAll === "number" ? meta.totalAll : 0,
        },
      };
    } catch (err) {
      if (err?.code === "ERR_CANCELED") {
        return { data: [], meta: { total: 0, totalAll: 0 } };
      }
      const message =
        err?.response?.data?.message ??
        err?.message ??
        "Failed to load table data.";
      error.value = message;
      return { data: [], meta: { total: 0, totalAll: 0 } };
    } finally {
      if (controller === currentController) {
        loading.value = false;
      }
    }
  }

  /** Refetch using last payload (or initialOptions). No-op if no payload available. */
  async function refetch() {
    if (lastPayload) {
      await fetch(lastPayload);
    }
  }

  return { rows, total, totalAll, loading, error, fetch, fetchPage, refetch };
}
