import { nocodb } from '../config';

let discoveredTables: Record<string, string> | null = null;

async function fetchJson(url: string, options: RequestInit = {}): Promise<unknown> {
  const res = await fetch(url, {
    ...options,
    headers: {
      'xc-token': nocodb.token,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });
  if (!res.ok) {
    const text = await res.text().catch(() => '');
    throw new Error(`NocoDB ${res.status}: ${text.slice(0, 200)}`);
  }
  return res.json();
}

export async function discoverTableIds(): Promise<Record<string, string>> {
  if (discoveredTables) return discoveredTables;
  if (!nocodb.baseId) throw new Error('NOCODB_BASE_ID not configured');

  const json = await fetchJson(
    `${nocodb.url}/api/v2/meta/bases/${nocodb.baseId}/tables`
  ) as { list: Array<{ title: string; id: string }> };

  const tables: Record<string, string> = {};
  for (const t of json.list) {
    tables[t.title] = t.id;
  }

  discoveredTables = tables;
  return tables;
}

export async function deleteRowsByMonth(tableId: string, yearMonth: string): Promise<number> {
  // Fetch all row IDs for the given month using a where filter
  const where = `(Date,like,${yearMonth}%)`;
  let deleted = 0;
  let hasMore = true;

  while (hasMore) {
    const json = await fetchJson(
      `${nocodb.url}/api/v2/tables/${tableId}/records?where=${encodeURIComponent(where)}&limit=100&fields=Id`
    ) as { list: Array<{ Id: number }> };

    const ids = json.list.map(r => r.Id);
    if (ids.length === 0) {
      hasMore = false;
      break;
    }

    // Bulk delete
    await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
      method: 'DELETE',
      body: JSON.stringify(ids.map(Id => ({ Id }))),
    });

    deleted += ids.length;
  }

  return deleted;
}

export async function deleteAllRows(tableId: string): Promise<number> {
  let deleted = 0;
  let hasMore = true;

  while (hasMore) {
    const json = await fetchJson(
      `${nocodb.url}/api/v2/tables/${tableId}/records?limit=100&fields=Id`
    ) as { list: Array<{ Id: number }> };

    const ids = json.list.map(r => r.Id);
    if (ids.length === 0) {
      hasMore = false;
      break;
    }

    await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
      method: 'DELETE',
      body: JSON.stringify(ids.map(Id => ({ Id }))),
    });

    deleted += ids.length;
  }

  return deleted;
}

export async function insertRecords<T extends Record<string, unknown>>(tableId: string, records: T[]): Promise<number> {
  const batchSize = 100;
  let inserted = 0;

  for (let i = 0; i < records.length; i += batchSize) {
    const batch = records.slice(i, i + batchSize);
    await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
      method: 'POST',
      body: JSON.stringify(batch),
    });
    inserted += batch.length;
  }

  return inserted;
}

// Generic CRUD helpers

export async function fetchAllRecords<T>(tableId: string): Promise<T[]> {
  let all: T[] = [];
  let offset = 0;

  while (true) {
    const json = await fetchJson(
      `${nocodb.url}/api/v2/tables/${tableId}/records?limit=1000&offset=${offset}`
    ) as { list: T[] };

    all = all.concat(json.list);
    if (json.list.length < 1000) break;
    offset += 1000;
  }

  return all;
}

export async function createRecord<T extends Record<string, unknown>>(tableId: string, record: T): Promise<T> {
  return await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
    method: 'POST',
    body: JSON.stringify(record),
  }) as T;
}

export async function updateRecord<T extends Record<string, unknown>>(tableId: string, id: number, record: T): Promise<T> {
  return await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
    method: 'PATCH',
    body: JSON.stringify({ Id: id, ...record }),
  }) as T;
}

export async function deleteRecord(tableId: string, id: number): Promise<void> {
  await fetchJson(`${nocodb.url}/api/v2/tables/${tableId}/records`, {
    method: 'DELETE',
    body: JSON.stringify([{ Id: id }]),
  });
}
