/**
 * @fileoverview Tests for RPC generator and client-server separation
 */

import { describe, expect, it } from 'vitest';
import { OrdoJSCodeGenerator } from './code-generator-fixed.js';
import { RPCGenerator } from './rpc-generator.js';

describe('RPC Generator', () => {
  const rpcGenerator = new RPCGenerator({
    endpoint: '/api/rpc',
    timeout: 5000,
    retries: 2,
    errorHandling: 'throw',
    authentication: true
  });

  // Mock component AST with server functions
  const mockAST: any = {
    component: {
      name: 'TestComponent',
      serverBlock: {
        functions: [
          {
            name: 'fetchData',
            parameters: [
              { name: 'id', isOptional: false, dataType: { name: 'string', isArray: false, isOptional: false, genericTypes: [] } },
              { name: 'filter', isOptional: true, dataType: { name: 'string', isArray: false, isOptional: true, genericTypes: [] } }
            ],
            returnType: { name: 'object', isArray: false, isOptional: false, genericTypes: [] },
            isAsync: true,
            isPublic: true,
            middleware: ['authMiddleware'],
            permissions: ['read:data']
          },
          {
            name: 'privateFunction',
            parameters: [],
            returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
            isAsync: false,
            isPublic: false,
            middleware: [],
            permissions: []
          }
        ]
      }
    }
  };

  it('should generate RPC stubs for public server functions', () => {
    const stubs = rpcGenerator.generateRPCStubs(mockAST);

    // Should only generate stubs for public functions
    expect(stubs.length).toBe(1);
    expect(stubs[0].functionName).toBe('fetchData');

    // Should include metadata
    expect(stubs[0].metadata.componentName).toBe('TestComponent');
    expect(stubs[0].metadata.parameters.length).toBe(2);
    expect(stubs[0].metadata.isAsync).toBe(true);

    // Should generate correct endpoint
    expect(stubs[0].serverEndpoint).toBe('/api/rpc/TestComponent/fetchData');

    // Client code should be a string containing the function implementation
    expect(typeof stubs[0].clientCode).toBe('string');
    expect(stubs[0].clientCode).toContain('async function fetchData');
    expect(stubs[0].clientCode).toContain('id, filter');
  });

  it('should generate client module with all RPC stubs', () => {
    const stubs = rpcGenerator.generateRPCStubs(mockAST);
    const clientModule = rpcGenerator.generateRPCClientModule(stubs, 'TestComponent');

    // Should generate a class with the component name
    expect(clientModule).toContain('export class TestComponentRPCClient');

    // Should include authentication helper when authentication is enabled
    expect(clientModule).toContain('function getAuthToken()');

    // Should export a default instance
    expect(clientModule).toContain('export default new TestComponentRPCClient()');
  });

  it('should generate server routes module', () => {
    const stubs = rpcGenerator.generateRPCStubs(mockAST);
    const serverModule = rpcGenerator.generateServerRoutesModule(stubs, 'TestComponent');

    // Should import the server component
    expect(serverModule).toContain("require('./testcomponent-server')");

    // Should create route handlers for each RPC endpoint
    expect(serverModule).toContain("app.post('/api/rpc/TestComponent/fetchData'");

    // Should include middleware checks
    expect(serverModule).toContain('await authMiddleware(req, res)');

    // Should include permission checks
    expect(serverModule).toContain('const requiredPermissions = ["read:data"]');
  });
});

describe('Code Generator with RPC Integration', () => {
  // Mock component AST with server functions
  const mockAST: any = {
    component: {
      name: 'TestComponent',
      serverBlock: {
        functions: [
          {
            name: 'fetchData',
            parameters: [
              { name: 'id', isOptional: false, dataType: { name: 'string', isArray: false, isOptional: false, genericTypes: [] } },
              { name: 'filter', isOptional: true, dataType: { name: 'string', isArray: false, isOptional: true, genericTypes: [] } }
            ],
            returnType: { name: 'object', isArray: false, isOptional: false, genericTypes: [] },
            isAsync: true,
            isPublic: true,
            middleware: ['authMiddleware'],
            permissions: ['read:data']
          }
        ]
      },
      clientBlock: {
        reactiveVariables: [],
        computedValues: [],
        eventHandlers: [],
        functions: [],
        lifecycle: []
      },
      markupBlock: {
        elements: [],
        textNodes: [],
        interpolations: []
      },
      props: []
    },
    dependencies: [],
    exports: [],
    sourceMap: {
      version: 3,
      sources: [],
      names: [],
      mappings: '',
      sourcesContent: []
    }
  };

  it('should integrate RPC generator in code generation', () => {
    // Create code generator with RPC options
    const codeGenerator = new OrdoJSCodeGenerator({
      minify: false,
      sourceMaps: true,
      target: 'development',
      rpcOptions: {
        endpoint: '/api/rpc',
        timeout: 5000,
        retries: 2,
        errorHandling: 'throw'
      }
    });

    // Generate client code
    const clientCode = codeGenerator.generateClientCode(mockAST);

    // Verify RPC stubs are generated in client code
    expect(clientCode).toContain('component.server = component.server || {}');
    expect(clientCode).toContain('component.server.fetchData = async function');
    expect(clientCode).toContain('/api/rpc/TestComponent/fetchData');
    expect(clientCode).toContain('const response = await fetch');
    expect(clientCode).toContain('return result');
  });

  it('should generate server code with RPC endpoints', () => {
    const codeGenerator = new OrdoJSCodeGenerator({
      minify: false,
      sourceMaps: true,
      target: 'development',
      rpcOptions: {
        endpoint: '/api/rpc'
      }
    });

    // Generate server code
    const serverCode = codeGenerator.generateServerCode(mockAST);

    // Verify server functions are exported
    expect(serverCode).toContain('public async function fetchData');
    expect(serverCode).toContain('serverModule.fetchData = fetchData');
  });
});
