/*
 * Runtime Web – Unified Serverless Framework for Full-Stack TypeScript Applications
 * Documentation: https://runtimeweb.com/docs/getting-started
 *
 * @template: ai-chat
 */

/**
 * Bedrock Service Property Tests
 *
 * Property-based tests for BedrockService temperature mapping and configuration.
 */

import * as fc from 'fast-check';

/**
 * Behavior mode to temperature mapping.
 * Validates: Requirements 8.2, 8.3, 10.3
 */
const BEHAVIOR_TEMPERATURE_MAP: Record<string, number> = {
    precise: 0.1,
    balanced: 0.5,
    creative: 0.9,
};

describe('Bedrock Service Properties', () => {
    /**
     * Feature: ai-chat-template, Property 14: Behavior Selector Value Passed to Backend
     *
     * For any behavior mode selection (precise/balanced/creative), the chat request
     * SHALL include the behavior value, and the Chat Handler SHALL map it to the
     * corresponding temperature value (precise=0.1, balanced=0.5, creative=0.9).
     *
     * **Validates: Requirements 8.2, 8.3, 8.4**
     */
    describe('Property 14: Behavior Selector Value Passed to Backend', () => {
        it('should map behavior modes to correct temperature values', async () => {
            await fc.assert(
                fc.asyncProperty(
                    fc.constantFrom('precise', 'balanced', 'creative'),
                    async (behavior) => {
                        const expectedTemperature = BEHAVIOR_TEMPERATURE_MAP[behavior];

                        // Verify the mapping exists and is correct
                        expect(expectedTemperature).toBeDefined();
                        expect(typeof expectedTemperature).toBe('number');

                        // Verify temperature is within valid range [0, 1]
                        expect(expectedTemperature).toBeGreaterThanOrEqual(0);
                        expect(expectedTemperature).toBeLessThanOrEqual(1);

                        // Verify specific mappings
                        if (behavior === 'precise') {
                            expect(expectedTemperature).toBe(0.1);
                        } else if (behavior === 'balanced') {
                            expect(expectedTemperature).toBe(0.5);
                        } else if (behavior === 'creative') {
                            expect(expectedTemperature).toBe(0.9);
                        }
                    }
                ),
                { numRuns: 100 }
            );
        });

        it('should use balanced temperature as default for unknown behaviors', async () => {
            await fc.assert(
                fc.asyncProperty(
                    fc.string().filter((s) => !['precise', 'balanced', 'creative'].includes(s)),
                    async (unknownBehavior) => {
                        const temperature = BEHAVIOR_TEMPERATURE_MAP[unknownBehavior] ?? 0.5;

                        // Unknown behaviors should default to balanced (0.5)
                        expect(temperature).toBe(0.5);
                    }
                ),
                { numRuns: 100 }
            );
        });

        it('should maintain temperature ordering: precise < balanced < creative', async () => {
            await fc.assert(
                fc.asyncProperty(fc.constant(null), async () => {
                    const preciseTemp = BEHAVIOR_TEMPERATURE_MAP['precise'];
                    const balancedTemp = BEHAVIOR_TEMPERATURE_MAP['balanced'];
                    const creativeTemp = BEHAVIOR_TEMPERATURE_MAP['creative'];

                    expect(preciseTemp).toBeLessThan(balancedTemp);
                    expect(balancedTemp).toBeLessThan(creativeTemp);
                }),
                { numRuns: 100 }
            );
        });
    });

    /**
     * Feature: ai-chat-template, Property 17: Model ID Configurable via Environment
     *
     * For any value of the BEDROCK_MODEL_ID environment variable, the BedrockService
     * SHALL use that value as the modelId in Bedrock API calls. If not set, it SHALL
     * default to 'anthropic.claude-3-sonnet-20240229-v1:0'.
     *
     * **Validates: Requirements 10.3, 10.4**
     */
    describe('Property 17: Model ID Configurable via Environment', () => {
        const DEFAULT_MODEL_ID = 'anthropic.claude-3-sonnet-20240229-v1:0';

        it('should use default model ID when environment variable is not set', async () => {
            await fc.assert(
                fc.asyncProperty(fc.constant(null), async () => {
                    // Simulate environment without BEDROCK_MODEL_ID
                    const modelId = process.env.BEDROCK_MODEL_ID || DEFAULT_MODEL_ID;

                    // When not set, should use default
                    if (!process.env.BEDROCK_MODEL_ID) {
                        expect(modelId).toBe(DEFAULT_MODEL_ID);
                    }
                }),
                { numRuns: 100 }
            );
        });

        it('should accept valid Bedrock model ID formats', async () => {
            const validModelIdArb = fc.oneof(
                fc.constant('anthropic.claude-3-sonnet-20240229-v1:0'),
                fc.constant('anthropic.claude-3-haiku-20240307-v1:0'),
                fc.constant('anthropic.claude-3-opus-20240229-v1:0'),
                fc.constant('anthropic.claude-instant-v1'),
                fc.constant('amazon.titan-text-express-v1')
            );

            await fc.assert(
                fc.asyncProperty(validModelIdArb, async (modelId) => {
                    // Valid model IDs should be non-empty strings
                    expect(typeof modelId).toBe('string');
                    expect(modelId.length).toBeGreaterThan(0);

                    // Should contain a provider prefix
                    expect(modelId).toMatch(/^(anthropic|amazon|meta|cohere)\./);
                }),
                { numRuns: 100 }
            );
        });

        it('should have a valid default model ID format', async () => {
            await fc.assert(
                fc.asyncProperty(fc.constant(null), async () => {
                    expect(DEFAULT_MODEL_ID).toBe('anthropic.claude-3-sonnet-20240229-v1:0');
                    expect(DEFAULT_MODEL_ID).toMatch(/^anthropic\./);
                    expect(DEFAULT_MODEL_ID).toContain('claude');
                }),
                { numRuns: 100 }
            );
        });
    });
});
