using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
namespace SqlSugar
{
    //局部类：拉姆达解析分类处理
    internal partial class ResolveExpress
    {
        private string UnaryExpression(Expression exp, ref MemberType type)
        {
            UnaryExpression ue = ((UnaryExpression)exp);
            var mex = ue.Operand;
            bool? isComparisonOperator = null;
            var isNot = ue.NodeType==ExpressionType.Not;
            if (mex.NodeType == ExpressionType.MemberAccess && isNot)
            {
                isComparisonOperator = false;
            }
            var cse = CreateSqlElements(mex, ref type, false,isComparisonOperator);
            if (type == MemberType.Value && isNot && cse.IsIn("1","0")) 
            {
                cse = cse == "1" ? "0" : "1";

            }else if (type == MemberType.None && isNot)
            {
                cse = " NOT " + cse;
            }
            return cse;
        }

        private bool UnderNodeTypeIsConstantExpression(MemberExpression exp)
        {
            while (exp.Expression != null)
            {
                if (exp != null && exp.Expression != null)
                {
                    if (exp.Expression is MemberExpression)
                    {
                        exp = (MemberExpression)exp.Expression;
                    }
                    else
                    {

                        break;
                    }
                }
            }
            return exp.Expression is ConstantExpression;
        }

        private string MemberExpression(ref Expression exp, ref MemberType type, bool? isComparisonOperator)
        {

            MemberExpression me = ((MemberExpression)exp);
            var isPro = (me.Member.Name == "Length") && me.Member.DeclaringType == PubConst.StringType;
            var proIsField = false;
            if (isPro) proIsField = me.Expression != null && !UnderNodeTypeIsConstantExpression(me);
            if (proIsField==false&&(me.Expression == null || me.Expression.NodeType != ExpressionType.Parameter))
            {
                type = MemberType.Value;
                object dynInv = null;

                if (isPro)
                {
                    exp = me.Expression;
                    dynInv = CreateSqlElements(exp, ref type, true);
                }
                else {
                    GetMemberValue(ref exp, me, ref dynInv);
                }
                if (isPro)return GetProMethod(me.Member.Name,dynInv.ObjToString(),false);
                if (dynInv!=null&&dynInv.GetType() == PubConst.BoolType)
                {
                    dynInv = ConstantBoolDictionary.Where(it => it.Type == PubConst.BoolType).Single(it => it.OldValue.ToLower() == dynInv.ObjToString().ToLower()).NewValue;
                }
                if (dynInv == null) return null;
                else
                    return dynInv.ToString();
            }
            else if (isComparisonOperator == false)
            {
                return "(" + me.Member.Name + "=1)";
            }
            else
            {
                if (Type == ResolveExpressType.Multiple)
                {
                    type = MemberType.Key;
                    var dbName = exp.ToString();
                    if (isPro) return GetProMethod(me.Member.Name, dbName, true);
                    return dbName;
                }
                //single T
                string name = me.Member.Name;
                if (isPro)
                {
                    name = ((me.Expression) as MemberExpression).Member.Name;
                }
                type = MemberType.Key;
                if (isPro) return GetProMethod(me.Member.Name, name, true);
                return name;
            }
        }

        private static void GetMemberValue(ref Expression exp, MemberExpression me, ref object dynInv)
        {
            // var dynInv = Expression.Lambda(exp).Compile().DynamicInvoke();原始写法性能极慢，下面写法性能提高了几十倍
            // var dynInv= Expression.Lambda(me.Expression as ConstantExpression).Compile().DynamicInvoke();
            SetMemberValueToDynInv(ref exp, me, ref dynInv);
            if (dynInv == ExpErrorUniqueKey)//特殊情况走原始写法
            {
                dynInv = Expression.Lambda(exp).Compile().DynamicInvoke();
                if (dynInv != null && dynInv.GetType().IsClass)
                {
                    dynInv = Expression.Lambda(me).Compile().DynamicInvoke();
                }
            }
        }

        private static string ConstantExpression(Expression exp, ref MemberType type, bool? isComparisonOperator)
        {
            type = MemberType.Value;
            ConstantExpression ce = ((ConstantExpression)exp);
            if (ce.Value == null)
                return "null";
            else if (ce.Value.ToString().IsIn("True", "False"))//是bool值
            {
                var ceType = ce.Value.GetType();
                var ceValue = ce.Value.ToString();
                if (isComparisonOperator==true)
                {
                    var ceNewValue = ConstantBoolDictionary.Single(it => it.Type == ceType && it.OldValue.ToLower() == ceValue.ToLower());
                    return ceNewValue.NewValue;
                }
                else
                {
                    var ceNewValue = ConstantBoolDictionary.Single(it => it.Type == ceType && it.OldValue.ToLower() == ceValue.ToLower());
                    return ceNewValue.Key.ToString();
                }
            }
            else
            {
                return ce.Value.ToString();
            }
        }

        private string MethodCallExpression(Expression exp, ref MemberType type, bool isTure)
        {
            MethodCallExpression mce = (MethodCallExpression)exp;
            string methodName = mce.Method.Name;
            if (methodName == "Contains")
            {
                return Contains(methodName, mce, isTure);
            }
            else if (methodName == "StartsWith")
            {
                return StartsWith(methodName, mce, isTure);
            }
            else if (methodName == "EndsWith")
            {
                return EndWith(methodName, mce, isTure);
            }
            else if (methodName == "ToString")
            {
                type = MemberType.Value;
                return MethodToString(methodName, mce, ref type);
            }
            else if (methodName == "IsNullOrEmpty")
            {
                type = MemberType.Value;
                return IsNullOrEmpty(methodName, mce, isTure);
            }
            else if (methodName == "Equals")
            {
                return Equals(methodName, mce);
            }
            else
            {
                type = MemberType.Value;
                return ParMethodTo(methodName, mce, ref type);
            }
        }

        private string BinaryExpression(Expression exp)
        {
            var expression = exp as BinaryExpression;
            var isComparisonOperator =
            expression.NodeType != ExpressionType.And &&
            expression.NodeType != ExpressionType.AndAlso &&
            expression.NodeType != ExpressionType.Or &&
            expression.NodeType != ExpressionType.OrElse;
            MemberType leftType = MemberType.None;
            MemberType rightType = MemberType.None;
            var leftIsDateTime = expression.Left.Type.ToString().Contains("System.DateTime");
            var rightIsDateTime = expression.Right.Type.ToString().Contains("System.DateTime");
            var left = CreateSqlElements(expression.Left, ref leftType, true, isComparisonOperator);
            var right = CreateSqlElements(expression.Right, ref rightType, true, isComparisonOperator);
            var oper = GetOperator(expression.NodeType);
            var isKeyOperValue = leftType == MemberType.Key && rightType == MemberType.Value;
            var isValueOperKey = rightType == MemberType.Key && leftType == MemberType.Value;
            #region 处理 null

            if (isKeyOperValue && right.IsGuid() && ConstantBoolDictionary.Any(it => it.Key.ToString() == right))
            {
                right = ConstantBoolDictionary.Single(it => it.Key.ToString() == right).NewValue;
            }
            if (isValueOperKey && ConstantBoolDictionary.Any(it => it.Key.ToString() == left))
            {
                left = ConstantBoolDictionary.Single(it => it.Key.ToString() == left).NewValue;
            }

            if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "=")
            {
                var oldLeft = AddParas(ref left, right);
                return string.Format(" ({0} is null ) ", oldLeft);
            }
            else if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "<>")
            {
                var oldLeft = AddParas(ref left, right);
                return string.Format(" ({0} is not null ) ", oldLeft);
            }
            else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "=")
            {
                return string.Format(" ({0} is null ) ", right);
            }
            else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "<>")
            {
                return string.Format(" ({0} is not null ) ", right);
            }
            #endregion
            else if (isKeyOperValue)
            {
                object parValue = null;
                if (leftIsDateTime && right != null && right.IsDate())
                {
                    parValue = Convert.ToDateTime(right);
                }
                else
                {
                    parValue = right;
                }
                if (left.Contains("("))
                {
                    return string.Format(" ({0} {1} {2}) ",left, oper, right.ToSqlValue());
                }
                else
                {
                    var oldLeft = AddParas(ref left, parValue);
                    return string.Format(" ({0} {1} " + this.ParSymbol + "{2}) ",this.SqlBuilder.GetTranslationColumnName(oldLeft), oper, left);
                }
            }
            else if (isValueOperKey)
            {
                object parValue = null;
                if (rightIsDateTime && left != null && left.IsDate())
                {
                    parValue = Convert.ToDateTime(left);
                }
                else
                {
                    parValue = left;
                }
                if (right.Contains("("))
                {
                    return string.Format(" ({0} {1} {2}) ", left.ToSqlValue(), oper, right);
                }
                else
                {
                    var oldRight = AddParasReturnRight(parValue, ref  right);
                    return string.Format("( " + this.ParSymbol + "{0} {1} {2} )", right, oper, this.SqlBuilder.GetTranslationColumnName(oldRight));
                }
            }
            else if (leftType == MemberType.Value && rightType == MemberType.Value)
            {
                var isAndOr = oper.ObjToString().IsIn("AND","OR");
                if (isAndOr)
                {
                    return string.Format("( {0} {1} {2} )", left, oper, right);
                }
                else
                {
                    return string.Format("( '{0}' {1} '{2}' )", left, oper, right);
                }
            }
            else
            {
                return string.Format("( {0} {1} {2} )", left, oper, right);
            }
        }

        private string LambdaExpression(Expression exp)
        {
            LambdaExpression lambda = exp as LambdaExpression;
            var expression = lambda.Body;
            MemberType EleType = MemberType.None;
            if (expression.NodeType == ExpressionType.MemberAccess) {
                return "("+((MemberExpression)expression).Member.Name+"=1)";
            }
            return CreateSqlElements(expression, ref EleType, true);
        }
    }
}
