// src/tests/integration/admin.integration.test.ts
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
import * as apiClient from '../../services/apiClient';
import { getPool } from '../../services/db/connection.db';
import type { User } from '../../types';

/**
 * @vitest-environment node
 */

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

describe('Admin API Routes Integration Tests', () => {
  let adminToken: string;
  let regularUser: User;
  let regularUserToken: string;
  

  beforeAll(async () => {
    // Log in as the pre-seeded admin user
    const adminLoginResponse = await apiClient.loginUser('admin@example.com', 'adminpass', false);
    const adminLoginData = await adminLoginResponse.json();
    adminToken = adminLoginData.token;

    // Create and log in as a new regular user for permission testing
    const regularUserEmail = `regular-user-${Date.now()}@example.com`;
    const registerResponse = await apiClient.registerUser(regularUserEmail, TEST_PASSWORD, 'Regular User');
    if (!registerResponse.ok) {
        const errorData = await registerResponse.json();
        throw new Error(errorData.message || 'Test registration failed');
    }
    const regularUserLoginResponse = await apiClient.loginUser(regularUserEmail, TEST_PASSWORD, false);
    const regularLoginData = await regularUserLoginResponse.json();
    regularUser = regularLoginData.user;
    regularUserToken = regularLoginData.token;

    // Cleanup the created user after all tests in this file are done
    return async () => {
      if (regularUser) {
        // First, delete dependent records, then delete the user.
        await getPool().query('DELETE FROM public.suggested_corrections WHERE user_id = $1', [regularUser.user_id]);
        await getPool().query('DELETE FROM public.users WHERE user_id = $1', [regularUser.user_id]);
      }
    };
  });

  describe('GET /api/admin/stats', () => {
    it('should allow an admin to fetch application stats', async () => {
      const response = await apiClient.getApplicationStats(adminToken);
      const stats = await response.json();
      expect(stats).toBeDefined();
      expect(stats).toHaveProperty('flyerCount');
      expect(stats).toHaveProperty('userCount');
      expect(stats).toHaveProperty('flyerItemCount');
    });

    it('should forbid a regular user from fetching application stats', async () => {
      const response = await apiClient.getApplicationStats(regularUserToken);
      expect(response.ok).toBe(false);
      expect(response.status).toBe(403);
      const errorData = await response.json();
      expect(errorData.message).toBe('Forbidden: Administrator access required.');
    });
  });

  describe('GET /api/admin/stats/daily', () => {
    it('should allow an admin to fetch daily stats', async () => {
      const response = await apiClient.getDailyStats(adminToken);
      const dailyStats = await response.json();
      expect(dailyStats).toBeDefined();
      expect(Array.isArray(dailyStats)).toBe(true);
      // The seed script creates users, so we should have some data
      expect(dailyStats.length).toBe(30);
      expect(dailyStats[0]).toHaveProperty('date');
      expect(dailyStats[0]).toHaveProperty('new_users');
      expect(dailyStats[0]).toHaveProperty('new_flyers');
    });

    it('should forbid a regular user from fetching daily stats', async () => {
      const response = await apiClient.getDailyStats(regularUserToken);
      expect(response.ok).toBe(false);
      expect(response.status).toBe(403);
      const errorData = await response.json();
      expect(errorData.message).toBe('Forbidden: Administrator access required.');
    });
  });

  describe('GET /api/admin/corrections', () => {
    it('should allow an admin to fetch suggested corrections', async () => {
      // This test just verifies access and correct response shape.
      // More detailed tests would require seeding corrections.
      const response = await apiClient.getSuggestedCorrections(adminToken);
      const corrections = await response.json();
      expect(corrections).toBeDefined();
      expect(Array.isArray(corrections)).toBe(true);
    });

    it('should forbid a regular user from fetching suggested corrections', async () => {
      const response = await apiClient.getSuggestedCorrections(regularUserToken);
      expect(response.ok).toBe(false);
      expect(response.status).toBe(403);
      const errorData = await response.json();
      expect(errorData.message).toBe('Forbidden: Administrator access required.');
    });
  });

  describe('GET /api/admin/brands', () => {
    it('should allow an admin to fetch all brands', async () => {
      const response = await apiClient.fetchAllBrands(adminToken);
      const brands = await response.json();
      expect(brands).toBeDefined();
      expect(Array.isArray(brands)).toBe(true);
      // The seed script creates brands
      expect(brands.length).toBeGreaterThan(0);
      expect(brands[0]).toHaveProperty('brand_id');
      expect(brands[0]).toHaveProperty('name');
    });

    it('should forbid a regular user from fetching all brands', async () => {
      const response = await apiClient.fetchAllBrands(regularUserToken);
      expect(response.ok).toBe(false);
      expect(response.status).toBe(403);
      const errorData = await response.json();
      expect(errorData.message).toBe('Forbidden: Administrator access required.');
    });
  });

  describe('Admin Data Modification Routes', () => {
    let testFlyerItemId: number;
    let testCorrectionId: number;

    // Before each modification test, create a fresh flyer item and a correction for it.
    beforeEach(async () => {
      // The seed script creates a flyer with ID 1 for Safeway.
      const flyerItemRes = await getPool().query(
        `INSERT INTO public.flyer_items (flyer_id, item, price_display, price_in_cents, quantity)
         VALUES (1, 'Test Item for Correction', '$1.99', 199, 'each') RETURNING flyer_item_id`
      );
      testFlyerItemId = flyerItemRes.rows[0].flyer_item_id;

      const correctionRes = await getPool().query(
        `INSERT INTO public.suggested_corrections (flyer_item_id, user_id, correction_type, suggested_value, status)
         VALUES ($1, $2, 'WRONG_PRICE', '250', 'pending') RETURNING suggested_correction_id`,
        [testFlyerItemId, regularUser.user_id]
      );
      testCorrectionId = correctionRes.rows[0].suggested_correction_id;
    });

    it('should allow an admin to approve a correction', async () => {
      // Act: Approve the correction.
      const response = await apiClient.approveCorrection(testCorrectionId, adminToken);
      expect(response.ok).toBe(true);

      // Assert: Verify the flyer item's price was updated and the correction status changed.
      const { rows: itemRows } = await getPool().query('SELECT price_in_cents FROM public.flyer_items WHERE flyer_item_id = $1', [testFlyerItemId]);
      expect(itemRows[0].price_in_cents).toBe(250);

      const { rows: correctionRows } = await getPool().query('SELECT status FROM public.suggested_corrections WHERE suggested_correction_id = $1', [testCorrectionId]);
      expect(correctionRows[0].status).toBe('approved');
    });

    it('should allow an admin to reject a correction', async () => {
      // Act: Reject the correction.
      const response = await apiClient.rejectCorrection(testCorrectionId, adminToken);
      expect(response.ok).toBe(true);

      // Assert: Verify the correction status changed.
      const { rows: correctionRows } = await getPool().query('SELECT status FROM public.suggested_corrections WHERE suggested_correction_id = $1', [testCorrectionId]);
      expect(correctionRows[0].status).toBe('rejected');
    });

    it('should allow an admin to update a correction', async () => {
      // Act: Update the suggested value of the correction.
      const response = await apiClient.updateSuggestedCorrection(testCorrectionId, '300', adminToken);
      const updatedCorrection = await response.json();

      // Assert: Verify the API response and the database state.
      expect(updatedCorrection.suggested_value).toBe('300');
      const { rows } = await getPool().query('SELECT suggested_value FROM public.suggested_corrections WHERE suggested_correction_id = $1', [testCorrectionId]);
      expect(rows[0].suggested_value).toBe('300');
    });

    it('should allow an admin to update a recipe status', async () => {
        // The seed script creates a recipe named 'Simple Chicken and Rice'.
        const { rows: recipeRows } = await getPool().query("SELECT recipe_id FROM public.recipes WHERE name = 'Simple Chicken and Rice'");
        if (recipeRows.length === 0) {
          throw new Error('Seed recipe "Simple Chicken and Rice" not found for test.');
        }
        const recipeId = recipeRows[0].recipe_id;

        // Act: Update the status to 'public'.
        const response = await apiClient.updateRecipeStatus(recipeId, 'public', adminToken);
        expect(response.ok).toBe(true);

        // Assert: Verify the status was updated in the database.
        const { rows: updatedRecipeRows } = await getPool().query('SELECT status FROM public.recipes WHERE recipe_id = $1', [recipeId]);
        expect(updatedRecipeRows[0].status).toBe('public');
    });
  });
});