/**
 * Tests for ReactGenerator
 */

import { ReactGenerator } from './react-generator';
import { WorkflowParser } from '../../parser/workflow-parser';
import { WorkflowEngine } from '../../engine/workflow-engine';
import * as path from 'path';

describe('ReactGenerator', () => {
  let generator: ReactGenerator;

  beforeEach(() => {
    generator = new ReactGenerator();
  });

  it('should have correct metadata', () => {
    expect(generator.id).toBe('react-frontend');
    expect(generator.name).toBe('React Frontend Generator');
    expect(generator.framework).toBe('react');
  });

  it('should generate empty result for workflow without frontend components', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test workflow',
      },
      stack: {
        api: {
          type: 'backend',
          technology: 'typescript/express',
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    expect(result.files).toHaveLength(0);
  });

  it('should generate React components from user-authentication workflow', async () => {
    const parser = new WorkflowParser();
    const workflowPath = path.join(__dirname, '../../../examples/user-authentication.workflow.yaml');
    const result = await parser.parseFile(workflowPath);

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(result.workflow);

    const genResult = generator.generate({
      workflow: result.workflow,
      executionPlan,
      outputDirectory: '/test',
    });

    // Should generate multiple files
    expect(genResult.files.length).toBeGreaterThan(0);

    // Should generate component file
    const componentFile = genResult.files.find(f => f.path.includes('LoginForm.tsx'));
    expect(componentFile).toBeDefined();
    expect(componentFile?.content).toContain('export const LoginForm');
    expect(componentFile?.content).toContain('useState');
    expect(componentFile?.content).toContain('apiClient');

    // Should generate CSS module
    const cssFile = genResult.files.find(f => f.path.includes('LoginForm.module.css'));
    expect(cssFile).toBeDefined();
    expect(cssFile?.content).toContain('.container');

    // Should generate types file
    const typesFile = genResult.files.find(f => f.path.includes('LoginForm.types.ts'));
    expect(typesFile).toBeDefined();
    expect(typesFile?.content).toContain('LoginFormProps');

    // Should generate API client
    const apiFile = genResult.files.find(f => f.path.includes('api/client.ts'));
    expect(apiFile).toBeDefined();
    expect(apiFile?.content).toContain('class ApiClient');

    // Should generate package.json
    const pkgFile = genResult.files.find(f => f.path.includes('package.json'));
    expect(pkgFile).toBeDefined();
    const pkg = JSON.parse(pkgFile?.content || '{}');
    expect(pkg.dependencies.react).toBeDefined();

    // Should generate main app file
    const mainFile = genResult.files.find(f => f.path.includes('main.tsx'));
    expect(mainFile).toBeDefined();
    expect(mainFile?.content).toContain('ReactDOM');
  });

  it('should generate component with state management', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test',
      },
      stack: {
        'web-app': {
          type: 'frontend',
          technology: 'react',
          components: [
            {
              id: 'test-form',
              name: 'TestForm',
              state: [
                { name: 'email', type: 'string', initial: '' },
                { name: 'isLoading', type: 'boolean', initial: false },
              ],
            },
          ],
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    const componentFile = result.files.find(f => f.path.includes('TestForm.tsx'));
    expect(componentFile).toBeDefined();
    expect(componentFile?.content).toContain('const [email, setEmail] = useState<string>("")');
    expect(componentFile?.content).toContain('const [isLoading, setIsLoading] = useState<boolean>(false)');
  });

  it('should generate form fields with proper inputs', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test',
      },
      stack: {
        'web-app': {
          type: 'frontend',
          technology: 'react',
          components: [
            {
              id: 'test-form',
              name: 'TestForm',
              ui: {
                fields: [
                  {
                    id: 'email-input',
                    type: 'email',
                    label: 'Email',
                    placeholder: 'Enter email',
                    validation: [{ required: true }],
                  },
                  {
                    id: 'submit-button',
                    type: 'button',
                    label: 'Submit',
                  },
                ],
              },
              state: [
                { name: 'email', type: 'string', initial: '' },
                { name: 'error', type: 'string', initial: '' },
                { name: 'isLoading', type: 'boolean', initial: false },
              ],
              actions: [
                {
                  id: 'handle-submit',
                  trigger: 'form-submit',
                  steps: [
                    {
                      id: 'submit-form',
                      action: 'api-call',
                      api_workflow: 'api.submit-endpoint',
                    },
                  ],
                },
              ],
            },
          ],
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    const componentFile = result.files.find(f => f.path.includes('TestForm.tsx'));
    expect(componentFile).toBeDefined();
    expect(componentFile?.content).toContain('<form');
    expect(componentFile?.content).toContain('type="email"');
    expect(componentFile?.content).toContain('placeholder="Enter email"');
    expect(componentFile?.content).toContain('required');
    expect(componentFile?.content).toContain('<button type="submit"');
    expect(componentFile?.content).toContain('Submit');
  });

  it('should generate API client with endpoint methods', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test',
      },
      stack: {
        'web-app': {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        api: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [
            {
              id: 'login-endpoint',
              path: '/api/auth/login',
              method: 'POST',
              request: {
                body: {
                  type: 'object',
                  required: ['email', 'password'],
                  properties: {
                    email: { type: 'string' },
                    password: { type: 'string' },
                  },
                },
              },
              responses: [
                {
                  status: 200,
                  body: {
                    type: 'object',
                    properties: {
                      token: { type: 'string' },
                    },
                  },
                },
              ],
            },
          ],
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    const apiFile = result.files.find(f => f.path.includes('api/client.ts'));
    expect(apiFile).toBeDefined();
    expect(apiFile?.content).toContain('class ApiClient');
    expect(apiFile?.content).toContain('async loginEndpoint');
    expect(apiFile?.content).toContain('email: string');
    expect(apiFile?.content).toContain('password: string');
    expect(apiFile?.content).toContain('/api/auth/login');
    expect(apiFile?.content).toContain("method: 'POST'");
  });

  it('should generate action handlers for API calls', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test',
      },
      stack: {
        'web-app': {
          type: 'frontend',
          technology: 'react',
          components: [
            {
              id: 'test-form',
              name: 'TestForm',
              state: [
                { name: 'email', type: 'string', initial: '' },
                { name: 'isLoading', type: 'boolean', initial: false },
              ],
              actions: [
                {
                  id: 'handle-submit',
                  trigger: 'form-submit',
                  steps: [
                    {
                      id: 'call-api',
                      action: 'api-call',
                      api_workflow: 'api.login-endpoint',
                      payload: {
                        email: '{{ state.email }}',
                      },
                      onStart: {
                        action: 'set-state',
                        target: 'isLoading',
                        value: true,
                      },
                      onSuccess: [
                        {
                          action: 'redirect',
                          path: '/dashboard',
                        },
                      ],
                      onError: [
                        {
                          action: 'set-state',
                          target: 'isLoading',
                          value: false,
                        },
                      ],
                    },
                  ],
                },
              ],
            },
          ],
        },
        api: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [
            {
              id: 'login-endpoint',
              path: '/api/auth/login',
              method: 'POST',
            },
          ],
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    const componentFile = result.files.find(f => f.path.includes('TestForm.tsx'));
    expect(componentFile).toBeDefined();
    expect(componentFile?.content).toContain('const handleSubmit = async');
    expect(componentFile?.content).toContain('e.preventDefault()');
    expect(componentFile?.content).toContain('setIsLoading(true)');
    expect(componentFile?.content).toContain('apiClient.loginEndpoint');
    expect(componentFile?.content).toContain('email: email');
    expect(componentFile?.content).toContain("window.location.href = '/dashboard'");
    expect(componentFile?.content).toContain('catch (error: any)');
  });

  it('should not overwrite package.json and tsconfig.json', () => {
    const workflow = {
      workflow: {
        id: 'test',
        name: 'Test',
        version: '1.0.0',
        description: 'Test',
      },
      stack: {
        'web-app': {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
      },
    };

    const engine = new WorkflowEngine();
    const executionPlan = engine.analyze(workflow as any);

    const result = generator.generate({
      workflow: workflow as any,
      executionPlan,
      outputDirectory: '/test',
    });

    const pkgFile = result.files.find(f => f.path.includes('package.json'));
    expect(pkgFile?.overwrite).toBe(false);

    const tsConfigFile = result.files.find(f => f.path.includes('tsconfig.json'));
    expect(tsConfigFile?.overwrite).toBe(false);
  });
});
