/**
 * @fileoverview Tests for the OrdoJS development server
 */

import http from 'http';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { OrdoJSDevServer, ServerStatus } from './server.js';

// Mock the http module
vi.mock('http', () => {
  const mockServer = {
    listen: vi.fn((port, host, callback) => {
      callback();
      return mockServer;
    }),
    close: vi.fn((callback) => {
      callback();
      return mockServer;
    }),
    address: vi.fn(() => ({ port: 3000 })),
    once: vi.fn(),
    on: vi.fn()
  };

  return {
    createServer: vi.fn(() => mockServer),
    Server: vi.fn(() => mockServer)
  };
});

// Mock the fs module
vi.mock('../utils/fs.js', () => ({
  fileExists: vi.fn().mockResolvedValue(true)
}));

// Mock the logger
vi.mock('../utils/logger.js', () => ({
  logger: {
    info: vi.fn(),
    success: vi.fn(),
    warn: vi.fn(),
    error: vi.fn(),
    debug: vi.fn()
  }
}));

describe('OrdoJSDevServer', () => {
  let server: OrdoJSDevServer;

  beforeEach(() => {
    server = new OrdoJSDevServer({
      dir: '.',
      host: 'localhost',
      port: 3000,
      hmr: true
    });

    // Reset mocks
    vi.clearAllMocks();
  });

  afterEach(async () => {
    try {
      await server.stop();
    } catch (error) {
      // Ignore errors during cleanup
    }
  });

  it('should initialize with correct options', () => {
    expect(server.getStatus()).toBe(ServerStatus.STOPPED);
  });

  it('should start the server successfully', async () => {
    await server.start();

    expect(server.getStatus()).toBe(ServerStatus.RUNNING);
    expect(http.createServer).toHaveBeenCalled();
    expect(server.getPort()).toBe(3000);
  });

  it('should stop the server successfully', async () => {
    await server.start();
    await server.stop();

    expect(server.getStatus()).toBe(ServerStatus.STOPPED);
  });

  it('should restart the server successfully', async () => {
    await server.start();
    await server.restart();

    expect(server.getStatus()).toBe(ServerStatus.RUNNING);
  });

  it('should preserve state during restart', async () => {
    await server.start();

    // Set some test state
    const testState = { testData: 'preserved data' };
    (server as any).serverState = testState;

    await server.restart();

    // Verify state was preserved
    expect(server.getServerState()).toEqual(testState);
    expect(server.getStatus()).toBe(ServerStatus.RUNNING);
  });

  it('should handle restart when already restarting', async () => {
    await server.start();

    // Set status to simulate already restarting
    (server as any).status = ServerStatus.RESTARTING;

    await server.restart();

    // Status should still be RESTARTING since the mock doesn't change it
    expect(server.getStatus()).toBe(ServerStatus.RESTARTING);
  });

  it('should handle multiple start calls gracefully', async () => {
    await server.start();
    await server.start(); // Second call should be ignored

    expect(server.getStatus()).toBe(ServerStatus.RUNNING);
    expect(http.createServer).toHaveBeenCalledTimes(1);
  });

  it('should handle multiple stop calls gracefully', async () => {
    await server.start();
    await server.stop();
    await server.stop(); // Second call should be ignored

    expect(server.getStatus()).toBe(ServerStatus.STOPPED);
  });
});
