import { BootstrapRecommendation } from '../types';
import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { vi } from 'vitest';

// We'll test the core logic without mocking child_process
// This is more realistic and avoids ESM mock issues

describe('Bootstrap Bootstrapper', () => {
  let testDir: string;

  beforeEach(async () => {
    testDir = join(tmpdir(), `bootstrap-test-${Date.now()}-${Math.random().toString(36).substring(7)}`);
    await fs.mkdir(testDir, { recursive: true });
  });

  afterEach(async () => {
    await fs.rm(testDir, { recursive: true, force: true });
  });

  describe('createBootstrapPlan', () => {
    // Import the function dynamically to avoid hoisting issues
    let createBootstrapPlan: any;
    
    beforeAll(async () => {
      const module = await import('../bootstrapper');
      createBootstrapPlan = module.createBootstrapPlan;
    });

    it('should sort recommendations by priority', () => {
      const recommendations: BootstrapRecommendation[] = [
        {
          id: 'low1',
          title: 'Low Priority',
          description: 'Low',
          priority: 'low',
          category: 'setup'
        },
        {
          id: 'high1',
          title: 'High Priority',
          description: 'High',
          priority: 'high',
          category: 'setup'
        },
        {
          id: 'medium1',
          title: 'Medium Priority',
          description: 'Medium',
          priority: 'medium',
          category: 'setup'
        }
      ];

      const plan = createBootstrapPlan(recommendations);
      
      expect(plan.recommendations[0].priority).toBe('high');
      expect(plan.recommendations[1].priority).toBe('medium');
      expect(plan.recommendations[2].priority).toBe('low');
    });

    it('should estimate time correctly', () => {
      const recommendations: BootstrapRecommendation[] = [
        { id: '1', title: 'High', description: '', priority: 'high', category: 'setup' },
        { id: '2', title: 'Medium', description: '', priority: 'medium', category: 'setup' },
        { id: '3', title: 'Low', description: '', priority: 'low', category: 'setup' }
      ];

      const plan = createBootstrapPlan(recommendations);
      
      // 5 + 3 + 2 = 10 minutes
      expect(plan.estimatedTime).toBe('10 minutes');
    });

    it('should detect when user input is required', () => {
      const recommendations: BootstrapRecommendation[] = [
        {
          id: 'create-license',
          title: 'Create License',
          description: 'Add license',
          priority: 'medium',
          category: 'documentation'
        }
      ];

      const plan = createBootstrapPlan(recommendations);
      
      expect(plan.requiresUserInput).toBe(true);
    });

    it('should handle empty recommendations', () => {
      const plan = createBootstrapPlan([]);
      
      expect(plan.recommendations).toEqual([]);
      expect(plan.estimatedTime).toBe('0 minutes');
      expect(plan.requiresUserInput).toBe(false);
    });
  });

  describe('executeRecommendation file operations', () => {
    let executeRecommendation: any;
    
    beforeAll(async () => {
      const module = await import('../bootstrapper');
      executeRecommendation = module.executeRecommendation;
    });

    it('should create files from recommendation', async () => {
      const recommendation: BootstrapRecommendation = {
        id: 'create-gitignore',
        title: 'Create .gitignore',
        description: 'Create gitignore file',
        priority: 'high',
        category: 'setup',
        files: [{
          path: '.gitignore',
          content: 'node_modules/',
          description: 'Gitignore file'
        }]
      };

      const result = await executeRecommendation(recommendation, testDir);
      
      expect(result.success).toBe(true);
      
      const fileContent = await fs.readFile(join(testDir, '.gitignore'), 'utf-8');
      expect(fileContent).toBe('node_modules/');
    });

    it('should create nested directories for files', async () => {
      const recommendation: BootstrapRecommendation = {
        id: 'setup-ci',
        title: 'Setup CI',
        description: 'Create CI workflow',
        priority: 'low',
        category: 'deployment',
        files: [{
          path: '.github/workflows/ci.yml',
          content: 'name: CI',
          description: 'CI workflow'
        }]
      };

      const result = await executeRecommendation(recommendation, testDir);
      
      expect(result.success).toBe(true);
      
      const fileContent = await fs.readFile(
        join(testDir, '.github/workflows/ci.yml'),
        'utf-8'
      );
      expect(fileContent).toBe('name: CI');
    });

    it('should handle multiple files in one recommendation', async () => {
      const recommendation: BootstrapRecommendation = {
        id: 'setup-linting',
        title: 'Setup Linting',
        description: 'Configure linting',
        priority: 'medium',
        category: 'development',
        files: [
          {
            path: '.eslintrc.json',
            content: '{"extends": ["standard"]}',
            description: 'ESLint config'
          },
          {
            path: '.prettierrc',
            content: '{"semi": true}',
            description: 'Prettier config'
          }
        ]
      };

      const result = await executeRecommendation(recommendation, testDir);
      
      expect(result.success).toBe(true);
      
      const eslintContent = await fs.readFile(join(testDir, '.eslintrc.json'), 'utf-8');
      const prettierContent = await fs.readFile(join(testDir, '.prettierrc'), 'utf-8');
      
      expect(eslintContent).toBe('{"extends": ["standard"]}');
      expect(prettierContent).toBe('{"semi": true}');
    });
  });

  describe('executeMultipleRecommendations', () => {
    let executeMultipleRecommendations: any;
    
    beforeAll(async () => {
      const module = await import('../bootstrapper');
      executeMultipleRecommendations = module.executeMultipleRecommendations;
    });

    it('should execute multiple file creation recommendations', async () => {
      const recommendations: BootstrapRecommendation[] = [
        {
          id: 'step1',
          title: 'Step 1',
          description: 'First step',
          priority: 'high',
          category: 'setup',
          files: [{
            path: 'step1.txt',
            content: 'Step 1',
            description: 'Step 1 file'
          }]
        },
        {
          id: 'step2',
          title: 'Step 2',
          description: 'Second step',
          priority: 'medium',
          category: 'setup',
          files: [{
            path: 'step2.txt',
            content: 'Step 2',
            description: 'Step 2 file'
          }]
        }
      ];

      const results = await executeMultipleRecommendations(recommendations, testDir);
      
      expect(results).toHaveLength(2);
      expect(results[0].success).toBe(true);
      expect(results[1].success).toBe(true);
      
      const file1 = await fs.readFile(join(testDir, 'step1.txt'), 'utf-8');
      const file2 = await fs.readFile(join(testDir, 'step2.txt'), 'utf-8');
      expect(file1).toBe('Step 1');
      expect(file2).toBe('Step 2');
    });

    it('should call progress callback', async () => {
      const progressCallback = vi.fn();
      const recommendations: BootstrapRecommendation[] = [
        {
          id: 'step1',
          title: 'Step 1',
          description: 'First',
          priority: 'high',
          category: 'setup',
          files: [{
            path: 'test.txt',
            content: 'test',
            description: 'Test file'
          }]
        }
      ];

      await executeMultipleRecommendations(
        recommendations,
        testDir,
        progressCallback
      );
      
      expect(progressCallback).toHaveBeenCalledTimes(1);
      expect(progressCallback).toHaveBeenCalledWith(
        expect.objectContaining({
          recommendationId: 'step1',
          success: true
        })
      );
    });
  });
});