import { analyzeProjectState, generateRecommendations, createBootstrapAnalysis } from '../analyzer';
import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { ProjectState } from '../types';

describe('Bootstrap Analyzer', () => {
  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('analyzeProjectState', () => {
    it('should detect git repository', async () => {
      await fs.mkdir(join(testDir, '.git'));
      const state = await analyzeProjectState(testDir);
      expect(state.hasGitRepo).toBe(true);
    });

    it('should detect package.json and parse it correctly', async () => {
      const packageJson = {
        name: 'test-project',
        scripts: {
          test: 'jest',
          build: 'tsc'
        },
        dependencies: {
          express: '^4.18.0'
        },
        devDependencies: {
          typescript: '^5.0.0',
          jest: '^29.0.0'
        }
      };
      
      await fs.writeFile(
        join(testDir, 'package.json'),
        JSON.stringify(packageJson, null, 2)
      );

      const state = await analyzeProjectState(testDir);
      
      expect(state.hasPackageJson).toBe(true);
      expect(state.hasTests).toBe(true);
      expect(state.hasBuildProcess).toBe(true);
      expect(state.hasTypeScript).toBe(true);
      expect(state.dependencies).toContain('express');
      expect(state.devDependencies).toContain('typescript');
      expect(state.scripts).toHaveProperty('test', 'jest');
    });

    it('should detect documentation folder', async () => {
      await fs.mkdir(join(testDir, 'docs'));
      const state = await analyzeProjectState(testDir);
      expect(state.hasDocumentation).toBe(true);
    });

    it('should detect CI configuration', async () => {
      await fs.mkdir(join(testDir, '.github', 'workflows'), { recursive: true });
      const state = await analyzeProjectState(testDir);
      expect(state.hasCI).toBe(true);
    });

    it('should detect linting setup', async () => {
      const packageJson = {
        devDependencies: {
          eslint: '^8.0.0'
        }
      };
      
      await fs.writeFile(
        join(testDir, 'package.json'),
        JSON.stringify(packageJson, null, 2)
      );

      const state = await analyzeProjectState(testDir);
      expect(state.hasLinting).toBe(true);
    });

    it('should return empty state for empty project', async () => {
      const state = await analyzeProjectState(testDir);
      
      expect(state.hasGitRepo).toBe(false);
      expect(state.hasPackageJson).toBe(false);
      expect(state.hasTests).toBe(false);
      expect(state.dependencies).toEqual([]);
      expect(state.devDependencies).toEqual([]);
    });
  });

  describe('generateRecommendations', () => {
    it('should recommend git init for project without git', () => {
      const state: ProjectState = {
        hasGitRepo: false,
        hasPackageJson: true,
        hasTests: false,
        hasDocumentation: false,
        hasCI: false,
        hasLinting: false,
        hasTypeScript: false,
        hasBuildProcess: false,
        hasReadme: false,
        hasLicense: false,
        hasGitIgnore: false,
        hasEnvironmentConfig: false,
        dependencies: [],
        devDependencies: [],
        scripts: {}
      };

      const recommendations = generateRecommendations(state);
      const gitRec = recommendations.find(r => r.id === 'init-git');
      
      expect(gitRec).toBeDefined();
      expect(gitRec?.priority).toBe('high');
      expect(gitRec?.command).toBe('git init');
    });

    it('should recommend TypeScript setup when missing', () => {
      const state: ProjectState = {
        hasGitRepo: true,
        hasPackageJson: true,
        hasTests: false,
        hasDocumentation: false,
        hasCI: false,
        hasLinting: false,
        hasTypeScript: false,
        hasBuildProcess: false,
        hasReadme: false,
        hasLicense: false,
        hasGitIgnore: false,
        hasEnvironmentConfig: false,
        dependencies: [],
        devDependencies: [],
        scripts: {}
      };

      const recommendations = generateRecommendations(state);
      const tsRec = recommendations.find(r => r.id === 'setup-typescript');
      
      expect(tsRec).toBeDefined();
      expect(tsRec?.priority).toBe('high');
      expect(tsRec?.devDependencies).toContain('typescript');
      expect(tsRec?.files).toBeDefined();
    });

    it('should recommend testing setup when missing', () => {
      const state: ProjectState = {
        hasGitRepo: true,
        hasPackageJson: true,
        hasTests: false,
        hasDocumentation: false,
        hasCI: false,
        hasLinting: false,
        hasTypeScript: true,
        hasBuildProcess: false,
        hasReadme: false,
        hasLicense: false,
        hasGitIgnore: false,
        hasEnvironmentConfig: false,
        dependencies: [],
        devDependencies: ['typescript'],
        scripts: {}
      };

      const recommendations = generateRecommendations(state);
      const testRec = recommendations.find(r => r.id === 'setup-testing');
      
      expect(testRec).toBeDefined();
      expect(testRec?.priority).toBe('high');
      expect(testRec?.devDependencies).toContain('jest');
      expect(testRec?.scripts).toHaveProperty('test');
    });

    it('should not recommend already configured items', () => {
      const state: ProjectState = {
        hasGitRepo: true,
        hasPackageJson: true,
        hasTests: true,
        hasDocumentation: true,
        hasCI: true,
        hasLinting: true,
        hasTypeScript: true,
        hasBuildProcess: true,
        hasReadme: true,
        hasLicense: true,
        hasGitIgnore: true,
        hasEnvironmentConfig: true,
        dependencies: [],
        devDependencies: ['typescript', 'jest', 'eslint'],
        scripts: { test: 'jest', build: 'tsc' }
      };

      const recommendations = generateRecommendations(state);
      expect(recommendations).toEqual([]);
    });
  });

  describe('createBootstrapAnalysis', () => {
    it('should create proper analysis summary', () => {
      const state: ProjectState = {
        hasGitRepo: false,
        hasPackageJson: false,
        hasTests: false,
        hasDocumentation: false,
        hasCI: false,
        hasLinting: false,
        hasTypeScript: false,
        hasBuildProcess: false,
        hasReadme: false,
        hasLicense: false,
        hasGitIgnore: false,
        hasEnvironmentConfig: false,
        dependencies: [],
        devDependencies: [],
        scripts: {}
      };

      const recommendations = generateRecommendations(state);
      const analysis = createBootstrapAnalysis(state, recommendations);

      expect(analysis.projectState).toBe(state);
      expect(analysis.recommendations).toBe(recommendations);
      expect(analysis.summary.totalRecommendations).toBeGreaterThan(0);
      expect(analysis.summary.highPriority).toBeGreaterThan(0);
    });
  });
});