// tests/api/03-flows.ts
// Flow Lifecycle Tests - Lazy and Eager Creation Patterns

import { api, log, runTest, saveImage, waitForGeneration, testContext, resolveAlias, exitWithTestResults } from './utils';
import { endpoints } from './config';

async function main() {
  log.section('FLOW LIFECYCLE TESTS');

  // Test 1: Lazy flow pattern - first generation without flowId
  await runTest('Lazy flow - generation without flowId', async () => {
    const result = await api(endpoints.generations, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        prompt: 'A red sports car on a mountain road',
        aspectRatio: '16:9',
        // NOTE: flowId not provided, should auto-generate
      }),
    });

    if (!result.data.data.flowId) {
      throw new Error('No flowId returned');
    }

    testContext.lazyFlowId = result.data.data.flowId;
    log.detail('Auto-generated flowId', testContext.lazyFlowId);

    const generation = await waitForGeneration(result.data.data.id);
    if (generation.status !== 'success') {
      throw new Error(`Generation failed`);
    }

    testContext.firstGenId = generation.id;
  });

  // Test 2: Lazy flow - verify flow doesn't exist yet (Section 4.1)
  await runTest('Lazy flow - verify flow not created yet', async () => {
    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}`, {
      expectError: true,
    });
    if (result.status !== 404) {
      throw new Error('Flow should not exist yet (lazy creation)');
    }
    log.detail('Flow correctly does not exist', '✓');
  });

  // Test 3: Lazy flow - second use creates flow
  await runTest('Lazy flow - second generation creates flow', async () => {
    const result = await api(endpoints.generations, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        prompt: 'Same car but blue color',
        aspectRatio: '16:9',
        flowId: testContext.lazyFlowId,
      }),
    });

    const generation = await waitForGeneration(result.data.data.id);
    if (generation.status !== 'success') {
      throw new Error(`Generation failed`);
    }

    // Now flow should exist
    const flowResult = await api(`${endpoints.flows}/${testContext.lazyFlowId}`);
    if (!flowResult.data.data) {
      throw new Error('Flow should exist after second use');
    }

    log.detail('Flow now exists', '✓');
    log.detail('Flow ID', flowResult.data.data.id);
  });

  // Test 4: Eager flow creation with flowAlias
  await runTest('Eager flow - created immediately with flowAlias', async () => {
    const result = await api(endpoints.generations, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        prompt: 'A hero banner image',
        aspectRatio: '21:9',
        flowAlias: '@hero-flow',
      }),
    });

    if (!result.data.data.flowId) {
      throw new Error('No flowId returned');
    }

    testContext.eagerFlowId = result.data.data.flowId;

    const generation = await waitForGeneration(result.data.data.id);
    if (generation.status !== 'success') {
      throw new Error(`Generation failed`);
    }

    // Flow should exist immediately
    const flowResult = await api(`${endpoints.flows}/${testContext.eagerFlowId}`);
    if (!flowResult.data.data) {
      throw new Error('Flow should exist immediately (eager creation)');
    }

    if (!flowResult.data.data.aliases || !flowResult.data.data.aliases['@hero-flow']) {
      throw new Error('Flow alias not set');
    }

    log.detail('Flow exists immediately', '✓');
    log.detail('Flow alias', '@hero-flow');
  });

  // Test 5: List all flows
  await runTest('List all flows', async () => {
    const result = await api(endpoints.flows);

    if (!result.data.data || !Array.isArray(result.data.data)) {
      throw new Error('No flows array returned');
    }

    const found = result.data.data.filter((f: any) =>
      f.id === testContext.lazyFlowId || f.id === testContext.eagerFlowId
    );

    if (found.length !== 2) {
      throw new Error('Not all created flows found');
    }

    log.detail('Total flows', result.data.data.length);
    log.detail('Our flows found', found.length);
  });

  // Test 6: Get flow details with computed counts
  await runTest('Get flow with computed counts', async () => {
    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}`);

    if (!result.data.data) {
      throw new Error('Flow not found');
    }

    const flow = result.data.data;

    if (typeof flow.generationCount !== 'number') {
      throw new Error('Missing generationCount');
    }

    if (typeof flow.imageCount !== 'number') {
      throw new Error('Missing imageCount');
    }

    log.detail('Generation count', flow.generationCount);
    log.detail('Image count', flow.imageCount);
    log.detail('Aliases', JSON.stringify(flow.aliases));
  });

  // Test 7: Get flow's generations
  await runTest('List flow generations', async () => {
    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}/generations`);

    if (!result.data.data || !Array.isArray(result.data.data)) {
      throw new Error('No generations array returned');
    }

    log.detail('Generations in flow', result.data.data.length);
  });

  // Test 8: Get flow's images
  await runTest('List flow images', async () => {
    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}/images`);

    if (!result.data.data || !Array.isArray(result.data.data)) {
      throw new Error('No images array returned');
    }

    log.detail('Images in flow', result.data.data.length);
  });

  // Test 9: Update flow aliases
  await runTest('Update flow aliases', async () => {
    // Get a generation to use
    const flowResult = await api(`${endpoints.flows}/${testContext.lazyFlowId}`);
    const gens = await api(`${endpoints.flows}/${testContext.lazyFlowId}/generations`);
    const lastGen = gens.data.data[0];

    if (!lastGen.outputImageId) {
      throw new Error('No output image');
    }

    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}/aliases`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        aliases: {
          '@latest': lastGen.outputImageId,
          '@best': lastGen.outputImageId,
        },
      }),
    });

    if (!result.data.data.aliases) {
      throw new Error('No aliases returned');
    }

    log.detail('Updated aliases', JSON.stringify(result.data.data.aliases));
  });

  // Test 10: Remove specific flow alias
  await runTest('Remove specific flow alias', async () => {
    await api(`${endpoints.flows}/${testContext.lazyFlowId}/aliases/@best`, {
      method: 'DELETE',
    });

    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}`);
    if ('@best' in result.data.data.aliases) {
      throw new Error('Alias should be removed');
    }

    if (!('@latest' in result.data.data.aliases)) {
      throw new Error('Other aliases should remain');
    }

    log.detail('Removed @best', '✓');
    log.detail('Kept @latest', '✓');
  });

  // Test 11: Flow regenerate endpoint
  await runTest('Regenerate flow (most recent generation)', async () => {
    const result = await api(`${endpoints.flows}/${testContext.lazyFlowId}/regenerate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({}),
    });

    if (!result.data.data) {
      throw new Error('No generation returned');
    }

    log.detail('Regeneration triggered', '✓');
    log.detail('Generation ID', result.data.data.id);
  });

  log.section('FLOW LIFECYCLE TESTS COMPLETED');
}

main()
  .then(() => exitWithTestResults())
  .catch((error) => {
    console.error('Unexpected error:', error);
    process.exit(1);
  });
