// values_and_flags_generators.js

/**
 * Values and flags Generators Definitions
 *
 * This file contains generator functions for each block defined in
 * values_and_flags.js. Each generator translates a Blockly block into a JSON
 * object representing info operations such as user notifications, variable
 * management, and flag operations.
 *
 * Note: This file assumes that `json_base_generator.js` has been loaded
 * before it, which initializes `Blockly.JSON` and attaches helper functions.
 */

export function defineVAFGenerators() {
    /**
     * Generator for 'notify_user' Block
     *
     * Description:
     * Generates a JSON object representing a user notification. Supports both
     * static text messages and dynamic values (variables, calculations, etc.).
     */
    Blockly.JSON['notify_user'] = function(block) {
        // Retrieve the 'MESSAGE' field input (static text)
        const message = block.getFieldValue('MESSAGE') || '';

        // Retrieve the connected VALUE block (dynamic value)
        const valueBlock = block.getInputTargetBlock('VALUE');
        let dynamicValue = null;

        if (valueBlock) {
            const generator = Blockly.JSON[valueBlock.type];
            if (typeof generator === 'function') {
                dynamicValue = generator(valueBlock);
            } else {
                console.warn(`No generator found for block type "${valueBlock.type}" in notify_user.`);
            }
        }

        // Validate: at least one of message or dynamicValue should be present
        if (message.trim() === "" && !dynamicValue) {
            console.warn("Empty MESSAGE and no VALUE in notify_user block. Defaulting to 'No message provided.'");
        }

        const json = {
            type: 'notify_user',
            message: message.trim(),
            value: dynamicValue
        };
        return json;
    };
    Blockly.JSON['value_input'] = function(block) {
        const values = []; // Initialize the values array

        /**
         * Recursively processes each block in the chain.
         *
         * @param {Blockly.Block} currentBlock - The current block to process.
         * @param {number} currentDepth - The current depth in the recursion.
         */
        function processBlock(currentBlock, currentDepth) {
            if (!currentBlock || currentDepth > 10) { // Enforce max depth and skip if block is missing
                if (currentDepth > 10) {
                    console.warn("Max depth exceeded in value_input chain. Stopping aggregation.");
                }
                return;
            }

            // Process 'VALUE' and add to values
            const valueJson = processConnectedBlock(currentBlock, 'VALUE');
            if (valueJson !== null) {
                // Flatten any nested dynamic_value objects
                if (valueJson && valueJson.type === 'dynamic_value' && Array.isArray(valueJson.values)) {
                    values.push(...valueJson.values);
                } else {
                    values.push(valueJson);
                }
            }

            // Process 'NEXT' block in the chain
            const nextBlock = currentBlock.getInputTargetBlock('NEXT');
            if (nextBlock) {
                const generator = Blockly.JSON[nextBlock.type];
                if (typeof generator === 'function') {
                    const generatedValue = generator(nextBlock);

                    // Flatten any nested dynamic_value objects
                    if (generatedValue && generatedValue.type === 'dynamic_value' && Array.isArray(generatedValue.values)) {
                        values.push(...generatedValue.values);
                    } else {
                        values.push(generatedValue);
                    }
                } else {
                    console.warn(`No generator found for block type "${nextBlock.type}". Skipping this block.`);
                }
            }
        }

        /**
         * Processes a connected block and retrieves its generated JSON or field value.
         *
         * @param {Blockly.Block} block - The current block to process.
         * @param {string} inputName - The input name to retrieve.
         * @returns {*} The processed value or null if invalid.
         */
        function processConnectedBlock(block, inputName) {
            const connectedBlock = block.getInputTargetBlock(inputName);
            if (connectedBlock) {
                const generator = Blockly.JSON[connectedBlock.type];
                if (typeof generator === 'function') {
                    const generatedValue = generator(connectedBlock);

                    // Flatten any nested dynamic_value objects
                    if (generatedValue && generatedValue.type === 'dynamic_value' && Array.isArray(generatedValue.values)) {
                        return generatedValue.values; // Return the values array directly
                    }
                    return generatedValue;
                }
                console.warn(`No generator found for block type "${connectedBlock.type}". Skipping this block.`);
                return null;
            }

            // If no connected block, parse field value as float
            let fieldValue = parseFloat(block.getFieldValue(inputName) || NaN);
            if (isNaN(fieldValue)) {
                fieldValue = block.getFieldValue(inputName);
            }
            return fieldValue;
        }

        processBlock(block, 1); // Start processing from the initial block

        // Build the JSON object without the skipAdditionalParsing flag
        const json = {
            type: 'dynamic_value',
            values: values.flat() // Flatten values array to handle nested arrays
        };

        console.log(`Generated JSON for 'value_input' block:`, json);
        return json;
    };



    /**
     * Generator for 'get_variable' Block
     *
     * Description:
     * Generates a JSON object representing a list of variable names.
     * Handles 'NEXT' inputs to support dynamic block chaining.
     *
     * @param {Block} block - The current block to generate JSON for.
     * @param {number|null} argsCount - Number of required variable names.
     *                                  null: Aggregate all connected blocks.
     *                                  n (positive integer): Aggregate up to 'n' variable names.
     * @param {number} maxDepth - A limit on the recursion depth to prevent infinite loops.
     * @returns {Object} The generated JSON object.
     */
    Blockly.JSON['get_variable'] = function(block, argsCount = null, maxDepth = 10) {
        // Initialize the variables array
        const variables = [];

        /**
         * Recursively processes each block in the chain.
         *
         * @param {Block} currentBlock - The current block to process.
         * @param {number} currentDepth - The current depth in the recursion.
         */
        function processBlock(currentBlock, currentDepth) {
            if (!currentBlock) {
                return;
            }

            if (currentDepth > maxDepth) {
                console.warn("Max depth exceeded in get_variable chain. Stopping aggregation.");
                return;
            }

            // Retrieve the 'variable_name' field input
            const variableName = currentBlock.getFieldValue('variable_name');
            const trimmedName = variableName && variableName.trim() !== "" ? variableName.trim() : 'undefined_var';
            if (variableName === "") {
                console.warn("Empty variable_name in get_variable block. Defaulting to 'undefined_var'.");
            }

            variables.push({
                type: 'get_variable',
                variable_name: trimmedName
            });

            // Process the 'NEXT' connection
            const nextBlock = currentBlock.getInputTargetBlock('NEXT');
            if (nextBlock) {
                const generator = Blockly.JSON[nextBlock.type];
                if (typeof generator === 'function') {
                    const generatedValue = generator(nextBlock, null, maxDepth - currentDepth);
                    if (generatedValue.type === 'dynamic_value' && Array.isArray(generatedValue.values)) {
                        variables.push(...generatedValue.values);
                    } else {
                        variables.push(generatedValue);
                    }
                } else {
                    console.warn(`No generator found for block type "${nextBlock.type}". Skipping this block.`);
                }
            }
        }

        // Start processing from the initial block
        processBlock(block, 1);

        // Construct the final JSON object as a dynamic_value
        return {
            type: 'dynamic_value',
            values: variables
        };
    };



    /**
     * Generator for 'set_variable' Block
     *
     * Description:
     * Generates a JSON object to assign a specific value or list of values to a variable.
     * Supports numerical, string, or dynamic values, enabling versatile usage.
     */
    Blockly.JSON['set_variable'] = function(block, argsCount = null, maxDepth = 10) {
        // Retrieve and validate the 'VAR_NAME' field input
        const varName = block.getFieldValue('VAR_NAME')?.trim() || 'undefined_var';

        if (varName === 'undefined_var') {
            console.warn("Empty VAR_NAME in set_variable block. Defaulting to 'undefined_var'.");
        }

        // Retrieve the connected block via 'VALUE' input
        const valueBlock = block.getInputTargetBlock('VALUE');
        let values = [];

        if (valueBlock) {
            const generator = Blockly.JSON[valueBlock.type];
            if (typeof generator === 'function') {
                // Invoke the generator for the connected block
                const generatedValue = generator(valueBlock, null, maxDepth - 1);

                // Handle different types of generated values
                if (generatedValue.type === 'dynamic_value' && Array.isArray(generatedValue.values)) {
                    // Assign the entire list
                    values = generatedValue.values;
                } else if (typeof generatedValue === 'object') {
                    // If it's an object, handle accordingly (customize as needed)
                    values.push(generatedValue);
                } else {
                    // For primitive types (number, string, etc.)
                    values.push(generatedValue);
                }
            } else {
                console.warn(`No generator found for block type "${valueBlock.type}". Skipping this block.`);
            }
        } else {
            console.warn("No connected block to 'VALUE' input in set_variable block. Defaulting to empty list.");
        }

        // Construct the JSON object for 'set_variable'
        const json = {
            type: 'set_variable',
            variable_name: varName,
            values: values
        };

        return json;
    };

    /**
     * Generator for 'set_flag' Block
     *
     * Description:
     * Generates a JSON object to assign a boolean value to a specified flag.
     * Flags can be used to control the flow of the strategy, trigger actions, or maintain state.
     */
    Blockly.JSON['set_flag'] = function(block) {
        // Retrieve the 'FLAG_NAME' field input
        const flagName = block.getFieldValue('FLAG_NAME');

        // Retrieve the 'FLAG_VALUE' dropdown selection
        const flagValue = block.getFieldValue('FLAG_VALUE'); // 'TRUE' or 'FALSE'

        // Validate the flag name
        if (!flagName || flagName.trim() === "") {
            console.warn("Empty FLAG_NAME in set_flag block. Defaulting to 'undefined_flag'.");
        }

        // Validate the flag value
        const validFlagValues = ['TRUE', 'FALSE'];
        if (!validFlagValues.includes(flagValue)) {
            console.warn(`Invalid FLAG_VALUE "${flagValue}" in set_flag block. Defaulting to 'FALSE'.`);
        }

        const json = {
            type: 'set_flag',
            flag_name: flagName && flagName.trim() !== "" ? flagName : 'undefined_flag',
            flag_value: validFlagValues.includes(flagValue) ? (flagValue === 'TRUE') : false
        };
        return json;
    };

    /**
     * Generator for 'flag_is_set' Block
     *
     * Description:
     * Generates a JSON object to evaluate whether a specified flag is set to True or False.
     * The output can be used in conditions to control the flow based on flag states.
     */
    Blockly.JSON['flag_is_set'] = function(block) {
        // Retrieve the 'FLAG_NAME' field input
        const flagName = block.getFieldValue('FLAG_NAME');

        // Retrieve the 'FLAG_VALUE' dropdown selection
        const flagValue = block.getFieldValue('FLAG_VALUE'); // 'TRUE' or 'FALSE'

        // Validate the flag name
        if (!flagName || flagName.trim() === "") {
            console.warn("Empty FLAG_NAME in flag_is_set block. Defaulting to 'undefined_flag'.");
        }

        // Validate the flag value
        const validFlagValues = ['TRUE', 'FALSE'];
        if (!validFlagValues.includes(flagValue)) {
            console.warn(`Invalid FLAG_VALUE "${flagValue}" in flag_is_set block. Defaulting to 'TRUE'.`);
        }

        const json = {
            type: 'flag_is_set',
            flag_name: flagName && flagName.trim() !== "" ? flagName : 'undefined_flag',
            flag_value: validFlagValues.includes(flagValue) ? (flagValue === 'TRUE') : true
        };

        return json;
    };
}
