/**
 * @fileoverview Tests for the deployment adapter manager
 */

import { describe, expect, it, vi } from 'vitest';
import { DeploymentAdapter, DeploymentConfig } from './adapter-interface.js';
import { DeploymentAdapterManager } from './adapter-manager.js';

// Create a mock adapter for testing
class MockAdapter implements DeploymentAdapter {
  name = 'mock';
  description = 'Mock adapter for testing';

  validateConfig(config: DeploymentConfig) {
    return { valid: true };
  }

  async prepareDeployment(config: DeploymentConfig) {
    return {
      success: true,
      generatedFiles: [
        { path: 'mock-config.json', content: '{}' }
      ],
      instructions: 'Mock deployment instructions'
    };
  }

  async optimizeForDeployment(config: DeploymentConfig, outputDir: string) {
    return {
      assets: [],
      totalOriginalSize: 0,
      totalMinifiedSize: 0,
      totalGzipSize: 0,
      totalBrotliSize: 0,
      overallCompressionRatio: 0,
      totalOriginalSizeHuman: '0 B',
      totalMinifiedSizeHuman: '0 B',
      totalGzipSizeHuman: '0 B',
      totalBrotliSizeHuman: '0 B'
    };
  }

  getEnvironmentVariables(config: DeploymentConfig) {
    return { MOCK: 'true' };
  }

  getDeployCommand(config: DeploymentConfig) {
    return 'mock deploy';
  }
}

// Mock the fs module
vi.mock('../fs.js', () => ({
  readFile: vi.fn(),
  writeFile: vi.fn(),
  mkdir: vi.fn()
}));

describe('DeploymentAdapterManager', () => {
  it('should register and retrieve adapters', () => {
    const manager = new DeploymentAdapterManager();
    const mockAdapter = new MockAdapter();

    manager.registerAdapter(mockAdapter);

    expect(manager.getAdapter('mock')).toBe(mockAdapter);
    expect(manager.getAllAdapters()).toContain(mockAdapter);
  });

  it('should set and get default adapter', () => {
    const manager = new DeploymentAdapterManager();
    const mockAdapter = new MockAdapter();

    manager.registerAdapter(mockAdapter);
    manager.setDefaultAdapter('mock');

    expect(manager.getDefaultAdapter()).toBe(mockAdapter);
  });

  it('should throw error when setting non-existent adapter as default', () => {
    const manager = new DeploymentAdapterManager();

    expect(() => manager.setDefaultAdapter('non-existent')).toThrow();
  });

  it('should prepare deployment using specified adapter', async () => {
    const manager = new DeploymentAdapterManager();
    const mockAdapter = new MockAdapter();
    const prepareDeploymentSpy = vi.spyOn(mockAdapter, 'prepareDeployment');

    manager.registerAdapter(mockAdapter);

    const config: DeploymentConfig = { outputDir: 'dist' };
    const result = await manager.prepareDeployment('mock', config);

    expect(result.success).toBe(true);
    expect(prepareDeploymentSpy).toHaveBeenCalledWith(config);
  });

  it('should return error when adapter not found', async () => {
    const manager = new DeploymentAdapterManager();

    const config: DeploymentConfig = { outputDir: 'dist' };
    const result = await manager.prepareDeployment('non-existent', config);

    expect(result.success).toBe(false);
    expect(result.error).toContain('not found');
  });

  it('should optimize for deployment using specified adapter', async () => {
    const manager = new DeploymentAdapterManager();
    const mockAdapter = new MockAdapter();
    const optimizeForDeploymentSpy = vi.spyOn(mockAdapter, 'optimizeForDeployment');

    manager.registerAdapter(mockAdapter);

    const config: DeploymentConfig = { outputDir: 'dist' };
    await manager.optimizeForDeployment('mock', config);

    expect(optimizeForDeploymentSpy).toHaveBeenCalledWith(config, 'dist');
  });

  it('should throw error when optimizing with non-existent adapter', async () => {
    const manager = new DeploymentAdapterManager();

    const config: DeploymentConfig = { outputDir: 'dist' };

    await expect(manager.optimizeForDeployment('non-existent', config)).rejects.toThrow();
  });
});
