const request = require('supertest');
const mongoose = require('mongoose');
const app = require('../server');
const Player = require('../models/Player');

describe('API Tests', () => {
  let token;
  let testUser;

  beforeAll(async () => {
    // Connect to test database
    const mongoUri = process.env.MONGODB_TEST_URI || 'mongodb://localhost:27017/galaxystrikeonline_test';
    await mongoose.connect(mongoUri);
  });

  afterAll(async () => {
    // Clean up and close connection
    await Player.deleteMany({});
    await mongoose.connection.close();
  });

  beforeEach(async () => {
    // Clean up before each test
    await Player.deleteMany({});
  });

  describe('Authentication', () => {
    test('POST /api/auth/register - should register new user', async () => {
      const userData = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'password123'
      };

      const response = await request(app)
        .post('/api/auth/register')
        .send(userData)
        .expect(201);

      expect(response.body).toHaveProperty('token');
      expect(response.body.user).toHaveProperty('username', userData.username);
      expect(response.body.user).toHaveProperty('email', userData.email);
    });

    test('POST /api/auth/login - should login existing user', async () => {
      // First register a user
      const userData = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'password123'
      };

      await request(app)
        .post('/api/auth/register')
        .send(userData);

      // Then login
      const loginData = {
        email: userData.email,
        password: userData.password
      };

      const response = await request(app)
        .post('/api/auth/login')
        .send(loginData)
        .expect(200);

      expect(response.body).toHaveProperty('token');
      token = response.body.token;
      testUser = response.body.user;
    });

    test('GET /api/auth/verify - should verify token', async () => {
      // First login to get token
      const userData = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'password123'
      };

      const registerResponse = await request(app)
        .post('/api/auth/register')
        .send(userData);

      token = registerResponse.body.token;

      const response = await request(app)
        .get('/api/auth/verify')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('valid', true);
      expect(response.body.user).toHaveProperty('username', userData.username);
    });
  });

  describe('Game API', () => {
    beforeEach(async () => {
      // Create and login a user for game tests
      const userData = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'password123'
      };

      const loginResponse = await request(app)
        .post('/api/auth/login')
        .send({
          email: userData.email,
          password: userData.password
        });

      token = loginResponse.body.token;
      testUser = loginResponse.body.user;
    });

    test('GET /api/game/player - should get player data', async () => {
      const response = await request(app)
        .get('/api/game/player')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('userId');
      expect(response.body).toHaveProperty('stats');
      expect(response.body).toHaveProperty('attributes');
    });

    test('GET /api/game/ships - should get player ships', async () => {
      const response = await request(app)
        .get('/api/game/ships')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('ships');
      expect(Array.isArray(response.body.ships)).toBe(true);
    });

    test('GET /api/game/inventory - should get player inventory', async () => {
      const response = await request(app)
        .get('/api/game/inventory')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('items');
      expect(response.body).toHaveProperty('summary');
    });

    test('POST /api/game/daily-reward - should claim daily reward', async () => {
      const response = await request(app)
        .post('/api/game/daily-reward')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('success');
    });
  });

  describe('Server API', () => {
    beforeEach(async () => {
      // Create and login a user for server tests
      const userData = {
        username: 'testuser',
        email: 'test@example.com',
        password: 'password123'
      };

      const loginResponse = await request(app)
        .post('/api/auth/login')
        .send({
          email: userData.email,
          password: userData.password
        });

      token = loginResponse.body.token;
      testUser = loginResponse.body.user;
    });

    test('GET /api/servers - should get server list', async () => {
      const response = await request(app)
        .get('/api/servers')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);

      expect(response.body).toHaveProperty('servers');
      expect(response.body).toHaveProperty('totalServers');
      expect(Array.isArray(response.body.servers)).toBe(true);
    });

    test('POST /api/servers/create - should create new server', async () => {
      const serverData = {
        name: 'Test Server',
        type: 'public',
        maxPlayers: 10,
        region: 'us-east'
      };

      const response = await request(app)
        .post('/api/servers/create')
        .set('Authorization', `Bearer ${token}`)
        .send(serverData)
        .expect(201);

      expect(response.body).toHaveProperty('message');
      expect(response.body.server).toHaveProperty('name', serverData.name);
      expect(response.body.server).toHaveProperty('type', serverData.type);
    });
  });

  describe('Health Check', () => {
    test('GET /health - should return health status', async () => {
      const response = await request(app)
        .get('/health')
        .expect(200);

      expect(response.body).toHaveProperty('status', 'OK');
      expect(response.body).toHaveProperty('timestamp');
      expect(response.body).toHaveProperty('uptime');
    });
  });
});
