import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { detectProject, summarizeDetection } from '../detect.js';

function createTempDir(): string {
  return fs.mkdtempSync(path.join(os.tmpdir(), 'web-dev-mcp-test-'));
}

describe('detectProject', () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = createTempDir();
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  it('detects a Laravel project', () => {
    fs.writeFileSync(path.join(tmpDir, 'composer.json'), JSON.stringify({ require: { 'laravel/framework': '^10.0' } }));
    fs.writeFileSync(path.join(tmpDir, 'artisan'), '#!/usr/bin/env php');
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('laravel');
    expect(detected.primary.kind).toBe('laravel');
  });

  it('detects a CodeIgniter project', () => {
    fs.writeFileSync(path.join(tmpDir, 'composer.json'), JSON.stringify({ require: { 'codeigniter4/framework': '^4.0' } }));
    fs.writeFileSync(path.join(tmpDir, 'spark'), '#!/usr/bin/env php');
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('codeigniter');
    expect(detected.primary.kind).toBe('codeigniter');
  });

  it('detects a React project', () => {
    fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ dependencies: { react: '^18.0' } }));
    const detected = detectProject(tmpDir);
    expect(detected.frontend?.kind).toBe('react');
    expect(detected.primary.kind).toBe('react');
  });

  it('detects a Vue project', () => {
    fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ dependencies: { vue: '^3.0' } }));
    const detected = detectProject(tmpDir);
    expect(detected.frontend?.kind).toBe('vue');
    expect(detected.primary.kind).toBe('vue');
  });

  it('detects Nuxt over Vue when both are present', () => {
    fs.writeFileSync(
      path.join(tmpDir, 'package.json'),
      JSON.stringify({ dependencies: { vue: '^3.0', nuxt: '^3.0' } }),
    );
    fs.writeFileSync(path.join(tmpDir, 'nuxt.config.ts'), 'export default {}\n');
    const detected = detectProject(tmpDir);
    expect(detected.frontend?.kind).toBe('nuxt');
  });

  it('detects Vue via .vue SFC + Vite when vue is not in package.json', () => {
    fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ scripts: { dev: 'vite' } }));
    fs.writeFileSync(path.join(tmpDir, 'vite.config.ts'), 'export default {}\n');
    const src = path.join(tmpDir, 'src');
    fs.mkdirSync(src);
    fs.writeFileSync(path.join(src, 'App.vue'), '<template><div /></template>\n');
    const detected = detectProject(tmpDir);
    expect(detected.frontend?.kind).toBe('vue');
  });

  it('detects a Symfony project', () => {
    fs.writeFileSync(
      path.join(tmpDir, 'composer.json'),
      JSON.stringify({ require: { 'symfony/framework-bundle': '^7.0' } }),
    );
    fs.mkdirSync(path.join(tmpDir, 'bin'));
    fs.writeFileSync(path.join(tmpDir, 'bin', 'console'), '#!/usr/bin/env php\n');
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('symfony');
  });

  it('detects a Django project', () => {
    fs.writeFileSync(path.join(tmpDir, 'manage.py'), '#!/usr/bin/env python\n');
    fs.writeFileSync(path.join(tmpDir, 'requirements.txt'), 'Django>=5.0\n');
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('django');
    expect(detected.primary.kind).toBe('django');
  });

  it('detects a Rails project', () => {
    fs.writeFileSync(path.join(tmpDir, 'Gemfile'), "gem 'rails', '~> 7.0'\n");
    fs.mkdirSync(path.join(tmpDir, 'bin'));
    fs.writeFileSync(path.join(tmpDir, 'bin', 'rails'), '#!/usr/bin/env ruby\n');
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('rails');
  });

  it('detects a Laravel backend with a separate React frontend', () => {
    fs.writeFileSync(path.join(tmpDir, 'composer.json'), JSON.stringify({ require: { 'laravel/framework': '^10.0' } }));
    fs.writeFileSync(path.join(tmpDir, 'artisan'), '#!/usr/bin/env php');
    const frontendDir = path.join(tmpDir, 'frontend');
    fs.mkdirSync(frontendDir);
    fs.writeFileSync(path.join(frontendDir, 'package.json'), JSON.stringify({ dependencies: { react: '^18.0' } }));
    const detected = detectProject(tmpDir);
    expect(detected.backend?.kind).toBe('laravel');
    expect(detected.frontend?.kind).toBe('react');
    expect(detected.primary.kind).toBe('laravel');
  });

  it('falls back to generic for an empty directory', () => {
    const detected = detectProject(tmpDir);
    expect(detected.backend).toBeNull();
    expect(detected.frontend).toBeNull();
    expect(detected.primary.kind).toBe('generic');
  });

  it('summarizeDetection returns serializable metadata', () => {
    fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ dependencies: { react: '^18.0' } }));
    const summary = summarizeDetection(detectProject(tmpDir));
    expect(summary.primary).toBe('react');
    expect(summary.combined).toBe(false);
    expect(summary.frontend).toHaveProperty('kind', 'react');
  });
});
