/**
 * @fileoverview Tests for the deploy command
 */

import { describe, expect, it, vi } from 'vitest';
import { DeploymentAdapterManager } from '../utils/deployment/index.js';
import { deployCommand } from './deploy.js';

// Mock the deployment adapter manager
vi.mock('../utils/deployment/index.js', () => {
  const mockAdapter = {
    name: 'mock',
    description: 'Mock adapter for testing',
    validateConfig: vi.fn().mockReturnValue({ valid: true }),
    prepareDeployment: vi.fn().mockResolvedValue({
      success: true,
      generatedFiles: [{ path: 'mock-config.json', content: '{}' }],
      instructions: 'Mock deployment instructions'
    }),
    optimizeForDeployment: vi.fn().mockResolvedValue({}),
    getEnvironmentVariables: vi.fn().mockReturnValue({}),
    getDeployCommand: vi.fn().mockReturnValue('mock deploy')
  };

  return {
    DeploymentAdapterManager: vi.fn().mockImplementation(() => ({
      registerAdapter: vi.fn(),
      getAdapter: vi.fn().mockReturnValue(mockAdapter),
      getAllAdapters: vi.fn().mockReturnValue([mockAdapter]),
      getDefaultAdapter: vi.fn().mockReturnValue(mockAdapter),
      setDefaultAdapter: vi.fn(),
      loadDeploymentConfig: vi.fn(),
      saveDeploymentConfig: vi.fn(),
      prepareDeployment: vi.fn(),
      optimizeForDeployment: vi.fn()
    })),
    VercelAdapter: vi.fn().mockImplementation(() => mockAdapter),
    NetlifyAdapter: vi.fn().mockImplementation(() => mockAdapter),
    AWSLambdaAdapter: vi.fn().mockImplementation(() => mockAdapter)
  };
});

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

// 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('Deploy Command', () => {
  it('should deploy with default options', async () => {
    const options = {
      adapter: 'vercel',
      dir: 'dist',
      env: {},
      static: false,
      server: false,
      production: false
    };

    await expect(deployCommand(options)).resolves.not.toThrow();

    // Check that the adapter manager was initialized
    expect(DeploymentAdapterManager).toHaveBeenCalled();

    // Check that adapters were registered
    const adapterManager = vi.mocked(DeploymentAdapterManager).mock.results[0].value;
    expect(adapterManager.registerAdapter).toHaveBeenCalledTimes(3);

    // Check that the adapter was retrieved
    expect(adapterManager.getAdapter).toHaveBeenCalledWith('vercel');

    // Check that deployment was prepared
    const adapter = adapterManager.getAdapter('vercel');
    expect(adapter.validateConfig).toHaveBeenCalled();
    expect(adapter.prepareDeployment).toHaveBeenCalled();
  });

  it('should deploy with custom options', async () => {
    const options = {
      adapter: 'netlify',
      dir: 'build',
      env: { API_URL: 'https://api.example.com' },
      static: true,
      server: true,
      production: true,
      domain: 'example.com'
    };

    await expect(deployCommand(options)).resolves.not.toThrow();

    // Check that the adapter was retrieved
    const adapterManager = vi.mocked(DeploymentAdapterManager).mock.results[0].value;
    expect(adapterManager.getAdapter).toHaveBeenCalledWith('netlify');

    // Check that deployment was prepared with correct config
    const adapter = adapterManager.getAdapter('netlify');
    expect(adapter.prepareDeployment).toHaveBeenCalledWith(expect.objectContaining({
      outputDir: 'build',
      isStatic: true,
      includeServerFunctions: true,
      env: { API_URL: 'https://api.example.com', NODE_ENV: 'production' },
      domain: { name: 'example.com', useHttps: true }
    }));
  });

  it('should handle deployment failure', async () => {
    // Mock the adapter to return a failed deployment
    const adapterManager = vi.mocked(DeploymentAdapterManager).mock.results[0].value;
    const adapter = adapterManager.getAdapter('vercel');
    vi.mocked(adapter.prepareDeployment).mockResolvedValueOnce({
      success: false,
      error: 'Deployment failed',
      generatedFiles: [],
      instructions: 'Error instructions'
    });

    const options = {
      adapter: 'vercel',
      dir: 'dist',
      env: {},
      static: false,
      server: false,
      production: false
    };

    await expect(deployCommand(options)).rejects.toThrow('Deployment failed');
  });
});
