import { describe, it, expect } from 'vitest';
import { generateFiles, type ProductManifest } from '../scaffolder.js';

function makeManifest(overrides: Partial<ProductManifest> = {}): ProductManifest {
  return {
    productId: 'testapp',
    displayName: 'TestApp',
    tagline: 'A test application',
    domain: 'testapp.dev',
    backendPort: 4050,
    primarySurface: 'web',
    platforms: ['web'],
    features: ['auth', 'telemetry'],
    ...overrides,
  };
}

describe('generateFiles', () => {
  it('generates root files', () => {
    const files = generateFiles(makeManifest());
    const paths = files.map(f => f.path);

    expect(paths).toContain('shared/product.json');
    expect(paths).toContain('.gitignore');
    expect(paths).toContain('.env.example');
    expect(paths).toContain('README.md');
  });

  it('always generates backend files', () => {
    const files = generateFiles(makeManifest());
    const paths = files.map(f => f.path);

    expect(paths).toContain('backend/package.json');
    expect(paths).toContain('backend/src/server.ts');
    expect(paths).toContain('backend/src/lib/config.ts');
    expect(paths).toContain('backend/src/lib/auth.ts');
    expect(paths).toContain('backend/src/lib/datastore.ts');
  });

  it('generates web files when platform includes web', () => {
    const files = generateFiles(makeManifest({ platforms: ['web'] }));
    const paths = files.map(f => f.path);

    expect(paths).toContain('web/package.json');
    expect(paths).toContain('web/next.config.ts');
    expect(paths).toContain('web/src/app/layout.tsx');
    expect(paths).toContain('web/src/app/page.tsx');
    expect(paths).toContain('web/src/lib/product-config.ts');
  });

  it('does not generate web files when platform excludes web', () => {
    const files = generateFiles(makeManifest({ platforms: ['mobile'] }));
    const paths = files.map(f => f.path);

    expect(paths).not.toContain('web/package.json');
    expect(paths).not.toContain('web/src/app/page.tsx');
  });

  it('generates mobile files when platform includes mobile', () => {
    const files = generateFiles(makeManifest({ platforms: ['mobile'] }));
    const paths = files.map(f => f.path);

    expect(paths).toContain('mobile/package.json');
    expect(paths).toContain('mobile/app.json');
    expect(paths).toContain('mobile/src/app/index.tsx');
  });

  it('does not generate mobile files when platform excludes mobile', () => {
    const files = generateFiles(makeManifest({ platforms: ['web'] }));
    const paths = files.map(f => f.path);

    expect(paths).not.toContain('mobile/package.json');
  });

  it('replaces product ID in generated content', () => {
    const files = generateFiles(makeManifest({ productId: 'myproduct' }));
    const productJson = files.find(f => f.path === 'shared/product.json')!;
    expect(productJson.content).toContain('"productId": "myproduct"');
  });

  it('replaces display name in generated content', () => {
    const files = generateFiles(makeManifest({ displayName: 'AwesomeApp' }));
    const readme = files.find(f => f.path === 'README.md')!;
    expect(readme.content).toContain('# AwesomeApp');
  });

  it('replaces backend port in config', () => {
    const files = generateFiles(makeManifest({ backendPort: 4099 }));
    const config = files.find(f => f.path === 'backend/src/lib/config.ts')!;
    expect(config.content).toContain('4099');
  });

  it('includes ios bundle ID when ios platform selected', () => {
    const files = generateFiles(makeManifest({ platforms: ['web', 'ios'], productId: 'myapp' }));
    const productJson = files.find(f => f.path === 'shared/product.json')!;
    expect(productJson.content).toContain('com.bytelyst.myapp');
  });

  it('includes android bundle ID when android platform selected', () => {
    const files = generateFiles(
      makeManifest({ platforms: ['web', 'android'], productId: 'myapp' })
    );
    const productJson = files.find(f => f.path === 'shared/product.json')!;
    expect(productJson.content).toContain('com.myapp.app');
  });

  it('includes backend env vars in .env.example', () => {
    const files = generateFiles(makeManifest({ backendPort: 4050 }));
    const env = files.find(f => f.path === '.env.example')!;
    expect(env.content).toContain('PORT=4050');
    expect(env.content).toContain('JWT_SECRET');
  });

  it('generates correct web product-config', () => {
    const files = generateFiles(makeManifest({ productId: 'testprod', backendPort: 4077 }));
    const webConfig = files.find(f => f.path === 'web/src/lib/product-config.ts')!;
    expect(webConfig.content).toContain("productId: 'testprod'");
    expect(webConfig.content).toContain('4077');
  });

  it('generates all platforms when all selected', () => {
    const files = generateFiles(makeManifest({ platforms: ['web', 'mobile', 'ios', 'android'] }));
    const paths = files.map(f => f.path);

    expect(paths).toContain('web/package.json');
    expect(paths).toContain('mobile/package.json');
    // Backend is always included
    expect(paths).toContain('backend/package.json');
  });

  it('server.ts includes display name in log message', () => {
    const files = generateFiles(makeManifest({ displayName: 'CoolProduct' }));
    const server = files.find(f => f.path === 'backend/src/server.ts')!;
    expect(server.content).toContain('CoolProduct backend listening');
  });
});
