// src/tests/integration/user.routes.integration.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import supertest from 'supertest';
import app from '../../../server';
import type { UserProfile } from '../../types';
import { createAndLoginUser } from '../utils/testHelpers';
import { cleanupDb } from '../utils/cleanup';

/**
 * @vitest-environment node
 */

const request = supertest(app);

let authToken = '';
let createdListId: number;
let testUser: UserProfile;

describe('User Routes Integration Tests (/api/users)', () => {
  // Authenticate once before all tests in this suite to get a JWT.
  beforeAll(async () => {
    // Use the helper to create and log in a user in one step.
    const { user, token } = await createAndLoginUser({
      fullName: 'User Routes Test User',
      request,
    });
    testUser = user;
    authToken = token;
  });

  afterAll(async () => {
    await cleanupDb({ userIds: testUser ? [testUser.user.user_id] : [] });
  });

  describe('GET /api/users/profile', () => {
    it('should return the profile for the authenticated user', async () => {
      const response = await request
        .get('/api/users/profile')
        .set('Authorization', `Bearer ${authToken}`);

      expect(response.status).toBe(200);
      expect(response.body).toBeDefined();
      expect(response.body.user.email).toBe(testUser.user.email);
      expect(response.body.role).toBe('user');
    });

    it('should return 401 Unauthorized if no token is provided', async () => {
      const response = await request.get('/api/users/profile');
      expect(response.status).toBe(401);
    });
  });

  describe('PUT /api/users/profile', () => {
    it('should update the user profile', async () => {
      const newName = `Test User ${Date.now()}`;
      const response = await request
        .put('/api/users/profile')
        .set('Authorization', `Bearer ${authToken}`)
        .send({ full_name: newName });

      expect(response.status).toBe(200);
      expect(response.body.full_name).toBe(newName);

      // Verify the change by fetching the profile again
      const verifyResponse = await request
        .get('/api/users/profile')
        .set('Authorization', `Bearer ${authToken}`);

      expect(verifyResponse.body.full_name).toBe(newName);
    });
  });

  describe('Shopping List CRUD', () => {
    it('POST /api/users/shopping-lists should create a new shopping list', async () => {
      const listName = `My Integration Test List ${Date.now()}`;
      const response = await request
        .post('/api/users/shopping-lists')
        .set('Authorization', `Bearer ${authToken}`)
        .send({ name: listName });

      expect(response.status).toBe(201);
      expect(response.body.name).toBe(listName);
      expect(response.body.shopping_list_id).toBeDefined();
      createdListId = response.body.shopping_list_id; // Save for the next test
    });

    it('GET /api/users/shopping-lists should retrieve the created shopping list', async () => {
      const response = await request
        .get('/api/users/shopping-lists')
        .set('Authorization', `Bearer ${authToken}`);

      expect(response.status).toBe(200);
      expect(Array.isArray(response.body)).toBe(true);
      const foundList = response.body.find(
        (list: { shopping_list_id: number }) => list.shopping_list_id === createdListId,
      );
      expect(foundList).toBeDefined();
    });

    it('DELETE /api/users/shopping-lists/:listId should delete the shopping list', async () => {
      expect(createdListId).toBeDefined(); // Ensure the previous test ran and set the ID

      const response = await request
        .delete(`/api/users/shopping-lists/${createdListId}`)
        .set('Authorization', `Bearer ${authToken}`);

      expect(response.status).toBe(204);

      // Verify deletion
      const verifyResponse = await request
        .get('/api/users/shopping-lists')
        .set('Authorization', `Bearer ${authToken}`);

      const foundList = verifyResponse.body.find(
        (list: { shopping_list_id: number }) => list.shopping_list_id === createdListId,
      );
      expect(foundList).toBeUndefined();
    });
  });

  describe('PUT /api/users/profile/preferences', () => {
    it('should update user preferences', async () => {
      const preferences = { darkMode: true, unitSystem: 'metric' };
      const response = await request
        .put('/api/users/profile/preferences')
        .set('Authorization', `Bearer ${authToken}`)
        .send(preferences);

      expect(response.status).toBe(200);
      expect(response.body.preferences).toEqual(preferences);

      // Verify the change by fetching the profile again
      const verifyResponse = await request
        .get('/api/users/profile')
        .set('Authorization', `Bearer ${authToken}`);

      expect(verifyResponse.body.preferences?.darkMode).toBe(true);
      expect(verifyResponse.body.preferences?.unitSystem).toBe('metric');
    });
  });
});
