// src/tests/integration/flyer.integration.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import supertest from 'supertest';
import { getPool } from '../../services/db/connection.db';
import app from '../../../server';
import type { Flyer, FlyerItem } from '../../types';

/**
 * @vitest-environment node
 */

describe('Public Flyer API Routes Integration Tests', () => {
  let flyers: Flyer[] = [];
  // Use a supertest instance for all requests in this file
  const request = supertest(app);
  let createdFlyerId: number;

  // Fetch flyers once before all tests in this suite to use in subsequent tests.
  beforeAll(async () => {
    // Ensure at least one flyer exists
    const storeRes = await getPool().query(
      `INSERT INTO public.stores (name) VALUES ('Integration Test Store') RETURNING store_id`,
    );
    const storeId = storeRes.rows[0].store_id;

    const flyerRes = await getPool().query(
      `INSERT INTO public.flyers (store_id, file_name, image_url, item_count, checksum) 
       VALUES ($1, 'integration-test.jpg', 'http://test.com/img.jpg', 1, $2) RETURNING flyer_id`,
      [storeId, `checksum-${Date.now()}`],
    );
    createdFlyerId = flyerRes.rows[0].flyer_id;

    // Add an item to it
    await getPool().query(
      `INSERT INTO public.flyer_items (flyer_id, item, price_display, price_in_cents, quantity)
       VALUES ($1, 'Integration Test Item', '$1.99', 199, 'each')`,
      [createdFlyerId],
    );

    const response = await request.get('/api/flyers');
    flyers = response.body;
  });

  describe('GET /api/flyers', () => {
    it('should return a list of flyers', async () => {
      // Act: Call the API endpoint using the client function.
      const response = await request.get('/api/flyers');
      const flyers: Flyer[] = response.body;
      expect(response.status).toBe(200);
      expect(flyers).toBeInstanceOf(Array);

      // We created a flyer in beforeAll, so we expect the array not to be empty.
      expect(flyers.length).toBeGreaterThan(0);

      // Check the shape of the first flyer object to ensure it matches the expected type.
      const firstFlyer = flyers[0];
      expect(firstFlyer).toHaveProperty('flyer_id');
      expect(firstFlyer).toHaveProperty('file_name');
      expect(firstFlyer).toHaveProperty('image_url');
      expect(firstFlyer).toHaveProperty('store');
      expect(firstFlyer.store).toHaveProperty('store_id');
      expect(firstFlyer.store).toHaveProperty('name');
    });
  });

  describe('GET /api/flyers/:id/items', () => {
    it('should return items for a specific flyer', async () => {
      // Arrange: Ensure we have at least one flyer to test with.
      expect(flyers.length).toBeGreaterThan(0);
      const testFlyer = flyers[0];

      // Act: Fetch items for the first flyer.
      const response = await request.get(`/api/flyers/${testFlyer.flyer_id}/items`);
      const items: FlyerItem[] = response.body;

      expect(response.status).toBe(200);
      expect(items).toBeInstanceOf(Array);

      // If there are items, check the shape of the first one.
      if (items.length > 0) {
        const firstItem = items[0];
        expect(firstItem).toHaveProperty('flyer_item_id');
        expect(firstItem).toHaveProperty('item');
        expect(firstItem).toHaveProperty('price_display');
        expect(firstItem.flyer_id).toBe(testFlyer.flyer_id);
      }
    });
  });

  describe('POST /api/flyers/items/batch-fetch', () => {
    it('should return items for multiple flyer IDs', async () => {
      // Arrange: Get IDs from the flyers fetched in beforeAll.
      const flyerIds = flyers.map((f) => f.flyer_id);
      expect(flyerIds.length).toBeGreaterThan(0);

      // Act: Fetch items for all available flyers.
      const response = await request.post('/api/flyers/items/batch-fetch').send({ flyerIds });
      const items: FlyerItem[] = response.body;
      expect(response.status).toBe(200);
      expect(items).toBeInstanceOf(Array);
      // The total number of items should be greater than or equal to the number of flyers (assuming at least one item per flyer).
      if (items.length > 0) {
        expect(items[0]).toHaveProperty('flyer_item_id');
      }
    });
  });

  describe('POST /api/flyers/items/batch-count', () => {
    it('should return the total count of items for multiple flyer IDs', async () => {
      // Arrange
      const flyerIds = flyers.map((f) => f.flyer_id);
      expect(flyerIds.length).toBeGreaterThan(0);

      // Act
      const response = await request.post('/api/flyers/items/batch-count').send({ flyerIds });
      const result = response.body;

      // Assert
      expect(result.count).toBeTypeOf('number');
      expect(result.count).toBeGreaterThan(0);
    });
  });
});
