import apiService from '../services/apiService';
import { toFrappeFilterArray } from './listFilterUtils';

/** Record filters (converted via `toFrappeFilterArray`) or raw Frappe filter arrays (e.g. `[['Sales Order','name','like','%x%']]`). */
export type FrappeListFiltersInput = Record<string, unknown> | unknown[][] | undefined;

function normalizeFilters(filters: FrappeListFiltersInput): unknown {
  if (filters == null) return {};
  if (Array.isArray(filters)) return filters.length > 0 ? filters : {};
  const fa = toFrappeFilterArray(filters as Record<string, any>);
  return fa.length > 0 ? fa : {};
}

export interface FetchAllRowsForExportArgs {
  doctype: string;
  filters?: FrappeListFiltersInput;
  orderBy?: string;
  fields?: string[];
  pageSize?: number;
  maxPages?: number;
  orFilters?: unknown[][];
}

/**
 * Page through `frappe.client.get_list` until all rows matching `filters` are loaded.
 * Matches list views that use filter objects or explicit filter tuples.
 */
export async function fetchAllRowsForExport(args: FetchAllRowsForExportArgs): Promise<any[]> {
  const {
    doctype,
    filters,
    orderBy = 'modified desc',
    fields = ['*'],
    pageSize = 100,
    maxPages = 100,
    orFilters,
  } = args;

  const norm = normalizeFilters(filters);
  const all: any[] = [];
  let page = 0;
  let hasMore = true;

  while (hasMore) {
    const body: Record<string, unknown> = {
      doctype,
      filters: norm,
      fields,
      limit_start: page * pageSize,
      limit_page_length: pageSize,
      order_by: orderBy,
    };
    if (orFilters && orFilters.length > 0) body.or_filters = orFilters;

    const csrf = await apiService.getCSRFToken();
    const headers: Record<string, string> = { 'Content-Type': 'application/json' };
    if (csrf) headers['X-Frappe-CSRF-Token'] = csrf;

    const res = await fetch('/api/method/frappe.client.get_list', {
      method: 'POST',
      headers,
      credentials: 'include',
      body: JSON.stringify(body),
    });

    const data = await res.json();
    if (data.exc) throw new Error(typeof data.exc === 'string' ? data.exc : 'get_list failed');
    if (!res.ok) throw new Error(typeof data.message === 'string' ? data.message : `get_list failed (${res.status})`);

    const batch: any[] = Array.isArray(data.message) ? data.message : [];
    all.push(...batch);
    if (batch.length < pageSize) hasMore = false;
    else {
      page += 1;
      if (page >= maxPages) {
        console.warn('[fetchAllRowsForExport] maxPages safety limit reached');
        hasMore = false;
      }
    }
  }

  return all;
}
