import request from 'supertest';
import app from '../src/server.js';
import { pool } from '../src/db/connection.js';

describe('API Contract Tests', () => {
  let authToken;
  let testUserId;

  beforeAll(async () => {
    // Clean up any existing test data
    await pool.query('DELETE FROM users WHERE email = ?', ['test@example.com']);
    
    // Register a test user
    const registerResponse = await request(app)
      .post('/auth/register')
      .send({
        email: 'test@example.com',
        password: 'password123',
        displayName: 'Test User'
      });
    
    expect(registerResponse.status).toBe(201);
    authToken = registerResponse.body.token;
    
    // Get the user ID
    const [rows] = await pool.query('SELECT id FROM users WHERE email = ?', ['test@example.com']);
    testUserId = rows[0].id;
  });

  afterAll(async () => {
    // Clean up test data
    await pool.query('DELETE FROM users WHERE email = ?', ['test@example.com']);
    await pool.end();
  });

  describe('Auth Endpoints', () => {
    it('should register a new user', async () => {
      const response = await request(app)
        .post('/auth/register')
        .send({
          email: 'register-test@example.com',
          password: 'password123',
          displayName: 'Register Test User'
        });
      
      expect(response.status).toBe(201);
      expect(response.body).toHaveProperty('token');
    });

    it('should fail to register with invalid data', async () => {
      const response = await request(app)
        .post('/auth/register')
        .send({
          email: 'invalid-email',
          password: 'short',
          displayName: ''
        });
      
      expect(response.status).toBe(400);
    });

    it('should login with valid credentials', async () => {
      const response = await request(app)
        .post('/auth/login')
        .send({
          email: 'test@example.com',
          password: 'password123'
        });
      
      expect(response.status).toBe(200);
      expect(response.body).toHaveProperty('token');
    });

    it('should fail to login with invalid credentials', async () => {
      const response = await request(app)
        .post('/auth/login')
        .send({
          email: 'test@example.com',
          password: 'wrongpassword'
        });
      
      expect(response.status).toBe(401);
    });
  });

  describe('Help Requests Endpoints', () => {
    let helpRequestId;

    it('should fetch all help requests', async () => {
      const response = await request(app)
        .get('/requests')
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(200);
      expect(Array.isArray(response.body)).toBe(true);
    });

    it('should create a new help request', async () => {
      const response = await request(app)
        .post('/requests')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'Test Help Request',
          description: 'This is a test help request',
          valueChf: 50.0
        });
      
      expect(response.status).toBe(201);
      expect(response.body).toHaveProperty('id');
      helpRequestId = response.body.id;
    });

    it('should fail to create a help request with invalid data', async () => {
      const response = await request(app)
        .post('/requests')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'T',
          description: 'Short',
          valueChf: -10
        });
      
      expect(response.status).toBe(400);
    });

    it('should update a help request', async () => {
      const response = await request(app)
        .put(`/requests/${helpRequestId}`)
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'Updated Test Help Request',
          description: 'This is an updated test help request',
          valueChf: 75.0,
          status: 'in_progress'
        });
      
      expect(response.status).toBe(200);
    });

    it('should fail to update a help request with invalid data', async () => {
      const response = await request(app)
        .put(`/requests/${helpRequestId}`)
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'T',
          description: 'Short',
          valueChf: -10
        });
      
      expect(response.status).toBe(400);
    });

    it('should delete a help request', async () => {
      const response = await request(app)
        .delete(`/requests/${helpRequestId}`)
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(200);
    });
  });

  describe('Offers Endpoints', () => {
    let offerId;

    it('should fetch all offers', async () => {
      const response = await request(app)
        .get('/offers')
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(200);
      expect(Array.isArray(response.body)).toBe(true);
    });

    it('should create a new offer', async () => {
      // First create a help request to offer against
      const requestResponse = await request(app)
        .post('/requests')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'Test Help Request for Offer',
          description: 'This is a test help request for an offer',
          valueChf: 50.0
        });
      
      const helpRequestId = requestResponse.body.id;
      
      const response = await request(app)
        .post('/offers')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          helpRequestId,
          description: 'This is a test offer',
          valueChf: 45.0
        });
      
      expect(response.status).toBe(201);
      expect(response.body).toHaveProperty('id');
      offerId = response.body.id;
    });

    it('should fail to create an offer with invalid data', async () => {
      const response = await request(app)
        .post('/offers')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          helpRequestId: 99999,
          description: 'Short',
          valueChf: -10
        });
      
      expect(response.status).toBe(400);
    });

    it('should delete an offer', async () => {
      const response = await request(app)
        .delete(`/offers/${offerId}`)
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(200);
    });
  });

  describe('Contacts Endpoints', () => {
    let helpRequestId;
    let offerId;

    beforeAll(async () => {
      // Create a help request and offer to have valid IDs for contact tests
      const requestResponse = await request(app)
        .post('/requests')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          title: 'Test Help Request for Contact',
          description: 'This is a test help request for contacts',
          valueChf: 50.0
        });
      
      helpRequestId = requestResponse.body.id;
      
      const offerResponse = await request(app)
        .post('/offers')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          helpRequestId,
          description: 'This is a test offer for contacts',
          valueChf: 45.0
        });
      
      offerId = offerResponse.body.id;
    });

    it('should fetch all contacts', async () => {
      const response = await request(app)
        .get('/contacts')
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(200);
      expect(Array.isArray(response.body)).toBe(true);
    });

    it('should create a new contact', async () => {
      const response = await request(app)
        .post('/contacts')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Test Contact',
          email: 'test@example.com',
          phone: '123-456-7890'
        });
      
      expect(response.status).toBe(201);
      expect(response.body).toHaveProperty('id');
    });

    it('should fail to create a contact with invalid data', async () => {
      const response = await request(app)
        .post('/contacts')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: '',
          email: 'invalid-email',
          phone: ''
        });
      
      expect(response.status).toBe(400);
    });

    it('should send a contact request', async () => {
      const response = await request(app)
        .post('/contacts/request')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          dealId: helpRequestId,
          targetUserId: testUserId
        });
      
      expect(response.status).toBe(403); // Forbidden because we're not in a valid deal context
    });

    it('should respond to a contact request', async () => {
      const response = await request(app)
        .post('/contacts/respond')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          requestId: 1,
          accept: true
        });
      
      expect(response.status).toBe(404); // Not found because we don't have a valid request ID
    });

    it('should fetch contacts for a deal', async () => {
      const response = await request(app)
        .get(`/contacts/deal/${helpRequestId}`)
        .set('Authorization', `Bearer ${authToken}`);
      
      expect(response.status).toBe(403); // Forbidden because we're not in a valid deal context
    });
  });
});