using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
using System;
using System.ComponentModel;
using System.Dynamic;
using System.Linq.Expressions;

namespace Serein.NodeFlow.Model
{
    /// <summary>
    /// 条件节点（用于条件控件）
    /// </summary>
    [NodeProperty(ValuePath = NodeValuePath.Node)]
    public partial class SingleConditionNode : NodeModelBase
    {
        /// <summary>
        /// 是否为自定义参数
        /// </summary>
        [PropertyInfo(IsNotification = true)]
        private bool _isExplicitData;

        /// <summary>
        /// 自定义参数值
        /// </summary>
        [PropertyInfo(IsNotification = true)]
        private string? _explicitData;

        /// <summary>
        /// 条件表达式
        /// </summary>
        [PropertyInfo(IsNotification = true)]
        private string _expression;

    }

    public partial class SingleConditionNode : NodeModelBase
    {
        /// <summary>
        /// 条件表达式节点是基础节点
        /// </summary>
        public override bool IsBase => true;

        /// <summary>
        /// 表达式参数索引
        /// </summary>
        private const int INDEX_EXPRESSION = 0;


        public SingleConditionNode(IFlowEnvironment environment):base(environment)
        {
            this.IsExplicitData = false;
            this.ExplicitData = string.Empty;
            this.Expression = "PASS";
        }

        public override void OnCreating()
        {
            // 这里的这个参数是为了方便使用入参控制点，参数无意义
            var pd = new ParameterDetails[1];
            pd[INDEX_EXPRESSION] = new ParameterDetails
            {
                Index = INDEX_EXPRESSION,
                Name = nameof(Expression),
                IsExplicitData = false,
                DataValue = string.Empty,
                DataType = typeof(string),
                ExplicitType = typeof(string),
                ArgDataSourceNodeGuid = string.Empty,
                ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
                NodeModel = this,
                //Convertor = null,
                InputType = ParameterValueInputType.Input,
                Items = null,
                Description = "条件节点入参控制点"
            };
            this.MethodDetails.ParameterDetailss = [..pd];
        }


        /// <summary>
        /// 导出方法信息
        /// </summary>
        /// <param name="nodeInfo"></param>
        /// <returns></returns>
        public override NodeInfo SaveCustomData(NodeInfo nodeInfo)
        {
            dynamic data = new ExpandoObject();
            data.Expression = Expression ?? "";
            data.ExplicitData = ExplicitData ?? "";
            data.IsExplicitData = IsExplicitData;
            nodeInfo.CustomData = data;
            return nodeInfo;
        }

        /// <summary>
        /// 加载自定义数据
        /// </summary>
        /// <param name="nodeInfo"></param>
        public override void LoadCustomData(NodeInfo nodeInfo)
        {
            this.Expression = nodeInfo.CustomData?.Expression ?? "";
            this.ExplicitData = nodeInfo.CustomData?.ExplicitData ?? "";
            this.IsExplicitData = nodeInfo.CustomData?.IsExplicitData ?? false;
        }

        /// <summary>
        /// 重写节点的方法执行
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return new FlowResult(this, context);
            }
            // 接收上一节点参数or自定义参数内容
            object? parameter;
            object? result = null;

            if (!IsExplicitData) 
            {
                // 使用自动取参
                var pd = MethodDetails.ParameterDetailss[INDEX_EXPRESSION];
                var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
                if (hasNode)
                {
                    context.NextOrientation = ConnectionInvokeType.IsError;
                    return new FlowResult(this, context);
                }
                if (hasNode)
                {
                    return new FlowResult(this, context);
                }
                if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
                {
                    result = context.GetFlowData(argSourceNode).Value; // 使用自定义节点的参数
                }
                else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
                {
                    CancellationTokenSource cts = new CancellationTokenSource();
                    var nodeResult = await argSourceNode.ExecutingAsync(context, cts.Token);
                    result = nodeResult.Value;
                    cts?.Cancel();
                    cts?.Dispose();
                }
                else
                {
                    result = context.TransmissionData(this).Value;    // 条件节点透传上一节点的数据
                }
                parameter = result;  // 使用上一节点的参数

            }
            else
            {
                var exp = ExplicitData?.ToString();
                if (!string.IsNullOrEmpty(exp) && exp.StartsWith('@'))
                {
                    parameter = result; // 表达式获取上一节点数据
                    if (parameter is not null)
                    {
                        parameter = SerinExpressionEvaluator.Evaluate(exp, parameter, out _);
                    }
                }
                else
                {
                    parameter = ExplicitData;  // 使用自定义的参数
                }
            }

            bool judgmentResult = false;
            try
            {
                judgmentResult = SereinConditionParser.To(parameter, Expression);
                context.NextOrientation = judgmentResult ? ConnectionInvokeType.IsSucceed : ConnectionInvokeType.IsFail;
            }
            catch (Exception ex)
            {
                context.NextOrientation = ConnectionInvokeType.IsError;
                context.ExceptionOfRuning = ex;
            }

            SereinEnv.WriteLine(InfoType.INFO, $"{result} {Expression}  -> " + context.NextOrientation);
            //return result;
            return new FlowResult(this, context, judgmentResult);
        }



    }


}
