// tests/transformers/mappingTransformer.test.ts
import { MappingTransformer, MappingRule } from '../transformers/mappingTransformer'; // Using path alias @/*
import { PipelineContext } from '../core/interfaces';
import { createLogger } from '../utils/logger';

// Basic mock context
const mockContext: PipelineContext = {
    logger: createLogger({ level: 'silent' }), // Silence logger during tests
    runId: 'test-run',
};

describe('MappingTransformer', () => {
    it('should map fields according to basic rules', async () => {
        const rules: MappingRule[] = [
            { sourcePath: 'user.id', targetPath: 'userId' },
            { sourcePath: 'user.profile.email', targetPath: 'contact.email' },
            { sourcePath: 'nonExistent', targetPath: 'defaultValueField', defaultValue: 'default' },
        ];
        const transformer = new MappingTransformer(rules);

        const input = {
            user: { id: 123, profile: { email: 'test@example.com', name: 'Tester' } },
            other: 'data',
        };

        const expectedOutput = {
            userId: 123,
            contact: { email: 'test@example.com' },
            defaultValueField: 'default',
        };

        const output = await transformer.transform(input, mockContext);
        expect(output).toEqual(expectedOutput);
    });

    it('should apply transformation functions', async () => {
        const rules: MappingRule[] = [
            { sourcePath: 'value', targetPath: 'doubledValue', transform: (val) => val * 2 },
            { sourcePath: 'name', targetPath: 'upperName', transform: (name) => name.toUpperCase() },
             { sourcePath: 'name', targetPath: 'prefixedName', transform: async (name, input, ctx) => {
                 // Example async transform using context/input
                 await new Promise(r => setTimeout(r, 10)); // Simulate async work
                 return `<span class="math-inline">\{ctx\.runId\}\_</span>{name}`;
             }},
        ];
        const transformer = new MappingTransformer(rules);
        const input = { value: 5, name: 'tester' };
        const output = await transformer.transform(input, mockContext);

        expect(output.doubledValue).toBe(10);
        expect(output.upperName).toBe('TESTER');
         expect(output.prefixedName).toBe('test-run_tester');
    });

    it('should handle nested target paths', async () => {
        const rules: MappingRule[] = [
            { sourcePath: 'a', targetPath: 'nested.level.valueA' },
            { sourcePath: 'b', targetPath: 'nested.otherValueB' },
        ];
        const transformer = new MappingTransformer(rules);
        const input = { a: 1, b: 2 };
        const output = await transformer.transform(input, mockContext);

        expect(output).toEqual({
            nested: {
                level: { valueA: 1 },
                otherValueB: 2,
            },
        });
    });

     it('should handle errors in transform function gracefully (default value)', async () => {
         const rules: MappingRule[] = [
             {
                 sourcePath: 'data',
                 targetPath: 'processedData',
                 transform: (val) => { throw new Error('Transform failed!'); },
                 defaultValue: 'fallback'
             }
         ];
         const transformer = new MappingTransformer(rules);
         const input = { data: 'some data' };
         // We don't expect the transformer itself to throw, just log and use default
         const output = await transformer.transform(input, mockContext);
         expect(output.processedData).toBe('fallback');
         // Optionally spy on logger to ensure error was logged
     });
});