// Auto-generated by AutoCRUD Web Generator
import { getBaseUrl } from '../../lib/client';

/** Progress message for a single resource during migration. */
export interface MigrateProgress {
  resource_id: string;
  status: 'migrating' | 'success' | 'failed' | 'skipped';
  message?: string;
  error?: string;
  timestamp?: string;
}

/** Final summary after migration completes. */
export interface MigrateResult {
  total: number;
  success: number;
  failed: number;
  skipped: number;
  errors: Array<{ resource_id: string; error: string }>;
  timestamp?: string;
}

/**
 * Parse a JSONL streaming response and invoke callbacks for each message.
 *
 * Uses native `fetch` instead of Axios because Axios does not support
 * `ReadableStream` for JSONL streaming responses.
 *
 * Progress messages (containing `resource_id`) are forwarded to `onProgress`.
 * The final summary message (containing `total`) is returned as the resolved value.
 */
async function streamMigrate(
  url: string,
  onProgress?: (p: MigrateProgress) => void,
  signal?: AbortSignal,
): Promise<MigrateResult> {
  const response = await fetch(url, { method: 'POST', signal });
  if (!response.ok) {
    const text = await response.text().catch(() => response.statusText);
    throw new Error(`HTTP ${response.status}: ${text}`);
  }

  const reader = response.body!.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let result: MigrateResult | null = null;

  for (;;) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop()!; // keep the potentially incomplete last line

    for (const line of lines) {
      if (!line.trim()) continue;
      try {
        const data = JSON.parse(line);
        if ('total' in data && 'success' in data) {
          result = data as MigrateResult;
        } else if (onProgress) {
          onProgress(data as MigrateProgress);
        }
      } catch {
        // skip malformed lines
      }
    }
  }

  // Process any remaining buffer
  if (buffer.trim()) {
    try {
      const data = JSON.parse(buffer);
      if ('total' in data && 'success' in data) {
        result = data as MigrateResult;
      } else if (onProgress) {
        onProgress(data as MigrateProgress);
      }
    } catch {
      // skip
    }
  }

  if (!result) {
    throw new Error('No migration result received from server');
  }
  return result;
}

/**
 * Build the migration URL with optional revision_id query parameter.
 */
function buildMigrateUrl(
  base: string,
  modelName: string,
  action: 'test' | 'execute',
  revisionId?: string | null,
): string {
  const url = `${base}/${modelName}/migrate/${action}`;
  if (revisionId) {
    return `${url}?revision_id=${encodeURIComponent(revisionId)}`;
  }
  return url;
}

/** Revision scope for batch migration. */
export type RevisionScope =
  | null       // current revision only (default)
  | 'all'      // every revision of each resource
  | string;    // specific revision ID

export const migrateApi = {
  /**
   * Test migration (dry run) for a model.
   * No data is written — safe to run on production.
   *
   * @param revisionId - Revision scope: omit/null for current, "all" for every revision, or a specific ID.
   */
  test: (
    modelName: string,
    onProgress?: (p: MigrateProgress) => void,
    signal?: AbortSignal,
    revisionId?: RevisionScope,
  ): Promise<MigrateResult> =>
    streamMigrate(buildMigrateUrl(getBaseUrl(), modelName, 'test', revisionId), onProgress, signal),

  /**
   * Execute migration for a model.
   * Migrated data is written back to storage.
   *
   * @param revisionId - Revision scope: omit/null for current, "all" for every revision, or a specific ID.
   */
  execute: (
    modelName: string,
    onProgress?: (p: MigrateProgress) => void,
    signal?: AbortSignal,
    revisionId?: RevisionScope,
  ): Promise<MigrateResult> =>
    streamMigrate(buildMigrateUrl(getBaseUrl(), modelName, 'execute', revisionId), onProgress, signal),
};
