// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
// </auto-generated>
// ------------------------------------------------------------------------------

#nullable enable
#pragma warning disable IDE0005 // Extra using directive is ok.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Extensions.AI;

namespace Test.WorkflowProviders;

/// <summary>
/// This class provides a factory method to create a <see cref="Workflow" /> instance.
/// </summary>
/// <remarks>
/// The workflow defined here was generated from a declarative workflow definition.
/// Declarative workflows utilize Power FX for defining conditions and expressions.
/// To learn more about Power FX, see:
/// https://learn.microsoft.com/power-platform/power-fx/formula-reference-copilot-studio
/// </remarks>
public static class WorkflowProvider
{
    /// <summary>
    /// The root executor for a declarative workflow.
    /// </summary>
    internal sealed class MyWorkflowRootExecutor<TInput>(
        DeclarativeWorkflowOptions options,
        Func<TInput, ChatMessage> inputTransform) :
        RootExecutor<TInput>("my_workflow_Root", options, inputTransform)
        where TInput : notnull
    {
        protected override async ValueTask ExecuteAsync(TInput message, IWorkflowContext context, CancellationToken cancellationToken)
        {
            // Initialize variables
            await context.QueueStateUpdateAsync("Count", UnassignedValue.Instance, "Local").ConfigureAwait(false);
            await context.QueueStateUpdateAsync("LoopIndex", UnassignedValue.Instance, "Local").ConfigureAwait(false);
            await context.QueueStateUpdateAsync("LoopValue", UnassignedValue.Instance, "Local").ConfigureAwait(false);
        }
    }
    
    /// <summary>
    /// Loops over a list assignign the loop variable to "Local.LoopValue" variable.
    /// </summary>
    internal sealed class ForeachLoopExecutor(FormulaSession session) : ActionExecutor(id: "foreach_loop", session)
    {
        private int _index;
        private object[] _values = [];
    
        public bool HasValue { get; private set; }
    
        // <inheritdoc />
        protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
        {
            this._index = 0;
            object? evaluatedValue = await context.EvaluateValueAsync<object>("""["a", "b", "c", "d", "e", "f"]""").ConfigureAwait(false);
    
            if (evaluatedValue == null)
            {
                this._values = [];
                this.HasValue = false;
            }
            else
            if (evaluatedValue is IEnumerable evaluatedList)
            {
                this._values = [.. evaluatedList];
            }
            else
            {
                this._values = [evaluatedValue];
            }
    
            await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
    
            return default;
        }
    
        public async ValueTask TakeNextAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
        {
            if (this.HasValue = this._index < this._values.Length)
            {
                object value = this._values[this._index];
    
            await context.QueueStateUpdateAsync(key: "LoopValue", value: value, scopeName: "Local").ConfigureAwait(false);
            await context.QueueStateUpdateAsync(key: "LoopIndex", value: this._index, scopeName: "Local").ConfigureAwait(false);
    
                this._index++;
            }
        }
    
        public async ValueTask CompleteAsync(IWorkflowContext context, object? _, CancellationToken cancellationToken)
        {
            await this.ResetAsync(context, cancellationToken).ConfigureAwait(false);
        }
    
        private async ValueTask ResetAsync(IWorkflowContext context, CancellationToken cancellationToken)
        {
            await context.QueueStateUpdateAsync(key: "LoopValue", value: UnassignedValue.Instance, scopeName: "Local").ConfigureAwait(false);
            await context.QueueStateUpdateAsync(key: "LoopIndex", value: UnassignedValue.Instance, scopeName: "Local").ConfigureAwait(false);
        }
    }
    
    /// <summary>
    /// Assigns an evaluated expression, other variable, or literal value to the  "Local.Count" variable.
    /// </summary>
    internal sealed class SetVariableInnerExecutor(FormulaSession session) : ActionExecutor(id: "set_variable_inner", session)
    {
        // <inheritdoc />
        protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
        {
            object? evaluatedValue = await context.EvaluateValueAsync<object>("Local.Count + 1").ConfigureAwait(false);
            await context.QueueStateUpdateAsync(key: "Count", value: evaluatedValue, scopeName: "Local").ConfigureAwait(false);
    
            return default;
        }
    }
    
    /// <summary>
    /// Formats a message template and sends an activity event.
    /// </summary>
    internal sealed class SendActivityInnerExecutor(FormulaSession session) : ActionExecutor(id: "send_activity_inner", session)
    {
        // <inheritdoc />
        protected override async ValueTask<object?> ExecuteAsync(IWorkflowContext context, CancellationToken cancellationToken)
        {
            string activityText =
                await context.FormatTemplateAsync(
                    """
                    x{Local.Count} - {Local.LoopIndex}:{Local.LoopValue}
                    """
                );
            AgentResponse response = new([new ChatMessage(ChatRole.Assistant, activityText)]);
            await context.AddEventAsync(new AgentResponseEvent(this.Id, response)).ConfigureAwait(false);
    
            return default;
        }
    }
    
    public static Workflow CreateWorkflow<TInput>(
        DeclarativeWorkflowOptions options,
        Func<TInput, ChatMessage>? inputTransform = null) 
        where TInput : notnull
    {
        // Create root executor to initialize the workflow.
        inputTransform ??= (message) => DeclarativeWorkflowBuilder.DefaultTransform(message);
        MyWorkflowRootExecutor<TInput> myWorkflowRoot = new(options, inputTransform);
        DelegateExecutor myWorkflow = new(id: "my_workflow", myWorkflowRoot.Session);
        ForeachLoopExecutor foreachLoop = new(myWorkflowRoot.Session);
        DelegateExecutor foreachLoopNext = new(id: "foreach_loop_Next", myWorkflowRoot.Session, foreachLoop.TakeNextAsync);
        DelegateExecutor foreachLoopPost = new(id: "foreach_loop_Post", myWorkflowRoot.Session);
        DelegateExecutor foreachLoopStart = new(id: "foreach_loop_Start", myWorkflowRoot.Session);
        SetVariableInnerExecutor setVariableInner = new(myWorkflowRoot.Session);
        SendActivityInnerExecutor sendActivityInner = new(myWorkflowRoot.Session);
        DelegateExecutor endAll = new(id: "end_all", myWorkflowRoot.Session);
        DelegateExecutor foreachLoopEnd = new(id: "foreach_loop_End", myWorkflowRoot.Session, foreachLoop.CompleteAsync);

        // Define the workflow builder
        WorkflowBuilder builder = new(myWorkflowRoot);

        // Connect executors
        builder.AddEdge(myWorkflowRoot, myWorkflow);
        builder.AddEdge(myWorkflow, foreachLoop);
        builder.AddEdge(foreachLoop, foreachLoopNext);
        builder.AddEdge(foreachLoopNext, foreachLoopPost, (object? result) => !foreachLoop.HasValue);
        builder.AddEdge(foreachLoopNext, foreachLoopStart, (object? result) => foreachLoop.HasValue);
        builder.AddEdge(foreachLoopStart, setVariableInner);
        builder.AddEdge(setVariableInner, sendActivityInner);
        builder.AddEdge(foreachLoopPost, endAll);
        builder.AddEdge(sendActivityInner, foreachLoopEnd);
        builder.AddEdge(foreachLoopEnd, foreachLoopNext);

        // Build the workflow
        return builder.Build(validateOrphans: false);
    }
}