// src/tests/integration/ai.integration.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import * as apiClient from '../../services/apiClient';
import * as aiApiClient from '../../services/aiApiClient';
import fs from 'node:fs/promises';
import path from 'path';

/**
 * @vitest-environment node
 */

interface TestGeolocationCoordinates {
  latitude: number;
  longitude: number;
  accuracy: number;
  altitude: number | null;
  altitudeAccuracy: number | null;
  heading: number | null;
  speed: number | null;
  toJSON(): object;
}

const TEST_PASSWORD = 'a-much-stronger-password-for-testing-!@#$';

describe('AI API Routes Integration Tests', () => {
  let authToken: string;

  beforeAll(async () => {
    // Create and log in as a new user for authenticated tests
    const email = `ai-test-user-${Date.now()}@example.com`;
    await apiClient.registerUser(email, TEST_PASSWORD, 'AI Tester');
    const loginResponse = await apiClient.loginUser(email, TEST_PASSWORD, false);
    const { token: loginToken } = await loginResponse.json();
    authToken = loginToken;
  });

  afterAll(async () => {
    // Clean up any files created in the flyer-images directory during these tests.
    const uploadDir = path.resolve(__dirname, '../../../flyer-images');
    try {
      const files = await fs.readdir(uploadDir);
      // Target files created by the 'image' and 'images' multer instances.
      const testFiles = files.filter(f => f.startsWith('image-') || f.startsWith('images-'));
      for (const file of testFiles) {
        await fs.unlink(path.join(uploadDir, file));
      }
    } catch (error) {
      console.error('Error during AI integration test file cleanup:', error);
    }
  });

  it('POST /api/ai/check-flyer should return a boolean', async () => {
    const mockImageFile = new File(['content'], 'test.jpg', { type: 'image/jpeg' });
    const response = await aiApiClient.isImageAFlyer(mockImageFile, authToken);
    const result = await response.json();
    // The backend is stubbed to always return true for this check
    expect(result.is_flyer).toBe(true);
  });

  it('POST /api/ai/extract-address should return a stubbed address', async () => {
    const mockImageFile = new File(['content'], 'test.jpg', { type: 'image/jpeg' });
    const response = await aiApiClient.extractAddressFromImage(mockImageFile, authToken);
    const result = await response.json();
    expect(result.address).toBe("123 AI Street, Server City");
  });

  it('POST /api/ai/extract-logo should return a stubbed response', async () => {
    const mockImageFile = new File(['content'], 'test.jpg', { type: 'image/jpeg' });
    const response = await aiApiClient.extractLogoFromImage([mockImageFile], authToken);
    const result = await response.json();
    expect(result).toEqual({ store_logo_base_64: null });
  });

  it('POST /api/ai/quick-insights should return a stubbed insight', async () => {
    const response = await aiApiClient.getQuickInsights([], authToken);
    const result = await response.json();
    expect(result.text).toBe("This is a server-generated quick insight: buy the cheap stuff!");
  });

  it('POST /api/ai/deep-dive should return a stubbed analysis', async () => {
    const response = await aiApiClient.getDeepDiveAnalysis([], authToken);
    const result = await response.json();
    expect(result.text).toBe("This is a server-generated deep dive analysis. It is very detailed.");
  });

  it('POST /api/ai/search-web should return a stubbed search result', async () => {
    const response = await aiApiClient.searchWeb([], authToken);
    const result = await response.json();
    expect(result).toEqual({ text: "The web says this is good.", sources: [] });
  });

  it('POST /api/ai/plan-trip should return a stubbed trip plan', async () => {
    // The GeolocationCoordinates type requires more than just lat/lng.
    // We create a complete mock object to satisfy the type.
    const mockLocation: TestGeolocationCoordinates = {
      latitude: 48.4284,
      longitude: -123.3656,
      accuracy: 100,
      altitude: null,
      altitudeAccuracy: null,
      heading: null,
      speed: null,
      toJSON: () => ({}),
    };
    const response = await aiApiClient.planTripWithMaps([], undefined, mockLocation, authToken);
    const result = await response.json();
    expect(result).toBeDefined();
    // The AI service is mocked in unit tests, but in integration it might be live.
    // For now, we just check that we get a text response.
    expect(result.text).toBeTypeOf('string');
  });

  it('POST /api/ai/generate-image should reject because it is not implemented', async () => {
    // The backend for this is not stubbed and will throw an error.
    // This test confirms that the endpoint is protected and responds as expected to a failure.
    const response = await aiApiClient.generateImageFromText("a test prompt", authToken);
    expect(response.ok).toBe(false);
    expect(response.status).toBe(501);
  });

  it('POST /api/ai/generate-speech should reject because it is not implemented', async () => {
    // The backend for this is not stubbed and will throw an error.
    const response = await aiApiClient.generateSpeechFromText("a test prompt", authToken);
    expect(response.ok).toBe(false);
    expect(response.status).toBe(501);
  });
});