/**
 * Read-only adapter for the legacy NocoDB Port Nimara base.
 *
 * Used by the one-shot migration script (`scripts/migrate-from-nocodb.ts`)
 * to pull every Interest, Residential Interest, and Website Submission
 * row from the source-of-truth NocoDB tables. No mutations.
 *
 * Auth: `xc-token` header per NocoDB v2 API.
 *
 * The shape returned is a verbatim record of the row's fields - caller
 * is responsible for mapping to the new schema via `nocodb-transform.ts`.
 */

import { z } from 'zod';

// ─── Configuration ──────────────────────────────────────────────────────────

const ConfigSchema = z.object({
  url: z.string().url(),
  token: z.string().min(1),
});

export interface NocoDbConfig {
  url: string;
  token: string;
}

export function loadNocoDbConfig(env: NodeJS.ProcessEnv = process.env): NocoDbConfig {
  return ConfigSchema.parse({
    url: env.NOCODB_URL,
    token: env.NOCODB_TOKEN,
  });
}

// ─── Table identifiers ──────────────────────────────────────────────────────
//
// These IDs are stable per the NocoDB base - they were captured during the
// 2026-05-03 audit and won't change unless the base is rebuilt. If the
// base is reset, regenerate them from `getTablesList`.
export const NOCO_TABLES = {
  interests: 'mbs9hjauug4eseo',
  residentialInterests: 'mscfpwwwjuds4nt',
  websiteInterestSubmissions: 'mevkpcih67c6jsm',
  websiteContactFormSubmissions: 'mxk5cd0pmwnwlcl',
  websiteBerthEoiSupplements: 'mglmioo0ku8zgqj',
  berths: 'mczgos9hr3oa9qc',
  // Lives in a *separate* NocoDB base ("Expenses", p3hq2fxdevqcaq8) but the
  // v2 records API addresses tables by id, so no per-base config is needed.
  expenses: 'mxfcefkk4dqs6uq',
} as const;

// ─── HTTP shape ─────────────────────────────────────────────────────────────

interface NocoDbListResponse<T> {
  list: T[];
  pageInfo: {
    totalRows: number;
    page: number;
    pageSize: number;
    isFirstPage: boolean;
    isLastPage: boolean;
  };
}

/** A row's `Id` is always present. The rest of the fields vary per table. */
export type NocoDbRow = Record<string, unknown> & { Id: number };

// ─── Public API ─────────────────────────────────────────────────────────────

/**
 * Fetch all rows from a NocoDB table. Auto-paginates until the API
 * reports `isLastPage`. The legacy base is small (252 Interests rows
 * being the largest table) so we keep this simple - no streaming.
 */
export async function fetchAllRows(
  tableId: string,
  config: NocoDbConfig,
  pageSize = 250,
): Promise<NocoDbRow[]> {
  const all: NocoDbRow[] = [];
  let page = 1;
  // Hard cap to prevent infinite-loop bugs if pageInfo lies. Each page
  // pulls up to `pageSize` rows, so 200 pages * 250 = 50k rows is the
  // maximum we'll ever fetch from one table.
  const MAX_PAGES = 200;

  while (page <= MAX_PAGES) {
    const url = new URL(`${config.url}/api/v2/tables/${tableId}/records`);
    url.searchParams.set('limit', String(pageSize));
    url.searchParams.set('offset', String((page - 1) * pageSize));

    const res = await fetch(url, {
      headers: {
        'xc-token': config.token,
        accept: 'application/json',
      },
    });

    if (!res.ok) {
      throw new Error(
        `NocoDB fetch failed: ${res.status} ${res.statusText} - table ${tableId} page ${page}`,
      );
    }

    const json = (await res.json()) as NocoDbListResponse<NocoDbRow>;
    all.push(...json.list);

    if (json.pageInfo.isLastPage || json.list.length === 0) break;
    page += 1;
  }

  return all;
}

/**
 * Convenience snapshot - pulls every table the migration cares about
 * in parallel. Returned shape is the input the transform layer expects.
 */
export interface NocoDbSnapshot {
  interests: NocoDbRow[];
  residentialInterests: NocoDbRow[];
  websiteInterestSubmissions: NocoDbRow[];
  websiteContactFormSubmissions: NocoDbRow[];
  websiteBerthEoiSupplements: NocoDbRow[];
  berths: NocoDbRow[];
  /** From the separate "Expenses" base. Optional so test fixtures and other
   *  snapshot sources needn't provide it; `fetchSnapshot` always does. */
  expenses?: NocoDbRow[];
  fetchedAt: string;
}

export async function fetchSnapshot(config: NocoDbConfig): Promise<NocoDbSnapshot> {
  const [
    interests,
    residentialInterests,
    websiteInterestSubmissions,
    websiteContactFormSubmissions,
    websiteBerthEoiSupplements,
    berths,
    expenses,
  ] = await Promise.all([
    fetchAllRows(NOCO_TABLES.interests, config),
    fetchAllRows(NOCO_TABLES.residentialInterests, config),
    fetchAllRows(NOCO_TABLES.websiteInterestSubmissions, config),
    fetchAllRows(NOCO_TABLES.websiteContactFormSubmissions, config),
    fetchAllRows(NOCO_TABLES.websiteBerthEoiSupplements, config),
    fetchAllRows(NOCO_TABLES.berths, config),
    fetchAllRows(NOCO_TABLES.expenses, config),
  ]);

  return {
    interests,
    residentialInterests,
    websiteInterestSubmissions,
    websiteContactFormSubmissions,
    websiteBerthEoiSupplements,
    berths,
    expenses,
    fetchedAt: new Date().toISOString(),
  };
}
