using ButcherFactory.BO.Utils;
using Forks.EnterpriseServices.DomainObjects2;
using Forks.EnterpriseServices.DomainObjects2.DQuery;
using Forks.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ButcherFactory.BO
{
  public static class DmoSession
  {
    public static IDmoSessionWithTransaction New()
    {
      return Dmo.NewSession(BO.Utils.AppContext.ConnectInfo.SqlConnection);
    }
  }

  public static class Extensions
  {
    public static object EExecuteScalar(this DQueryDom query, IDmoSession session)
    {
      return session.ExecuteScalar(query);
    }

    public static object EExecuteScalar(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteScalar(session);
      }
    }

    public static T EExecuteScalar<T>(this DQueryDom query, IDmoSession session)
    {
      return (T)query.EExecuteScalar(session);
    }

    public static T EExecuteScalar<T>(this DQueryDom query)
    {
      return (T)query.EExecuteScalar();
    }

    public static Tuple<T1, T2> EExecuteScalar<T1, T2>(this DQueryDom query, IDmoSession session)
    {
      var list = query.EExecuteList<T1, T2>(session);
      if (list.Count == 0)
      {
        return null;
      }
#if DEBUG
      if (list.Count > 1)
      {
        throw new Exception(string.Format("期望返回1条记录实际返回{0}条", list.Count));
      }
#endif
      return list[0];
    }

    public static Tuple<T1, T2> EExecuteScalar<T1, T2>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteScalar<T1, T2>(session);
      }
    }

    public static Tuple<T1, T2, T3> EExecuteScalar<T1, T2, T3>(this DQueryDom query, IDmoSession session)
    {
      var list = query.EExecuteList<T1, T2, T3>(session);
      if (list.Count == 0)
      {
        return null;
      }
#if DEBUG
      if (list.Count > 1)
      {
        throw new Exception(string.Format("期望返回1条记录实际返回{0}条", list.Count));
      }
#endif
      return list[0];
    }

    public static Tuple<T1, T2, T3> EExecuteScalar<T1, T2, T3>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteScalar<T1, T2, T3>(session);
      }
    }

    public static T EExecuteScalar<T>(this DmoQuery query) where T : class
    {
      var result = query.EExecuteList();
      if (result.Count == 0)
      {
        return default(T);
      }
      if (result.Count > 1)
      {
        throw new Exception("ExecuteScalar返回多个数据");
      }
      return (T)result[0];
    }

    public static List<T> EExecuteList<T>(this DQueryDom query, IDmoSession session)
    {
      var list = new List<T>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          list.Add((T)reader[0]);
        }
      }
      return list;
    }

    public static List<T> EExecuteList<T>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteList<T>(session);
      }
    }

    public static List<TDmo> EExecuteDmoList<TDmo>(this DQueryDom query, IDmoSession session, params string[] fields) where TDmo : new()
    {
      var type = typeof(TDmo);
      PCheck.IsTrue(query.From.RootSource.Alias.DmoSource == DmoInfo.Get(type));

      var dmoInfo = DmoInfo.Get(type);
      if (fields.Length == 0)
      {

        fields = dmoInfo.Fields
          .Select((item) => item.Name).ToArray();
      }
#if DEBUG
      else
      {
        foreach (var filed in fields)
        {
          if (!dmoInfo.Fields.Contains(filed))
          {
            throw new Exception(string.Format("对象{0}上不存在字段{1}的定义", type.Name, filed));
          }
        }
      }
#endif

      if (query.Columns.Count == 0)
      {
        foreach (var filed in fields)
        {
          query.Columns.Add(DQSelectColumn.Field(filed));
        }
      }
      else if (query.Columns.Count != fields.Length)
      {
        throw new Exception("查询字段数量不匹配");
      }

      var indexSetDic = fields.ToDictionary((item) => Array.IndexOf<string>(fields, item), (item) => type.GetProperty(item).GetSetMethod());

      var list = new List<TDmo>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var dmo = new TDmo();
          list.Add(dmo);
          foreach (var pair in indexSetDic)
          {
            pair.Value.Invoke(dmo, new object[] { reader[pair.Key] });
          }
        }
      }
      return list;
    }

    public static List<TDmo> EExecuteDmoList<TDmo>(this DQueryDom query, params string[] fields) where TDmo : new()
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteDmoList<TDmo>(session, fields);
      }
    }

    public static List<Tuple<T1, T2>> EExecuteList<T1, T2>(this DQueryDom query, IDmoSession session)
    {
      var list = new List<Tuple<T1, T2>>();

      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var value = new Tuple<T1, T2>(
              (T1)reader[0],
              (T2)reader[1]);
          list.Add(value);
        }
      }
      return list;
    }

    public static List<Tuple<T1, T2>> EExecuteList<T1, T2>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteList<T1, T2>(session);
      }
    }

    public static List<Tuple<T1, T2, T3>> EExecuteList<T1, T2, T3>(this DQueryDom query, IDmoSession session)
    {
      var list = new List<Tuple<T1, T2, T3>>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var value = new Tuple<T1, T2, T3>(
              (T1)reader[0],
              (T2)reader[1],
              (T3)reader[2]);
          list.Add(value);
        }
      }
      return list;
    }

    public static List<Tuple<T1, T2, T3>> EExecuteList<T1, T2, T3>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteList<T1, T2, T3>(session);
      }
    }

    public static List<Tuple<T1, T2, T3, T4>> EExecuteList<T1, T2, T3, T4>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteList<T1, T2, T3, T4>(session);
      }
    }

    public static List<Tuple<T1, T2, T3, T4>> EExecuteList<T1, T2, T3, T4>(this DQueryDom query, IDmoSession session)
    {
      var list = new List<Tuple<T1, T2, T3, T4>>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var value = new Tuple<T1, T2, T3, T4>(
              (T1)reader[0],
              (T2)reader[1],
              (T3)reader[2], (T4)reader[3]);
          list.Add(value);
        }
      }
      return list;
    }


    public static List<Tuple<T1, T2, T3, T4, T5>> EExecuteList<T1, T2, T3, T4, T5>(this DQueryDom query)
    {
      using (var session = DmoSession.New())
      {
        return query.EExecuteList<T1, T2, T3, T4, T5>(session);
      }
    }

    public static List<Tuple<T1, T2, T3, T4, T5>> EExecuteList<T1, T2, T3, T4, T5>(this DQueryDom query, IDmoSession session)
    {
      var list = new List<Tuple<T1, T2, T3, T4, T5>>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var value = new Tuple<T1, T2, T3, T4, T5>(
              (T1)reader[0],
              (T2)reader[1],
              (T3)reader[2], (T4)reader[3], (T5)reader[4]);
          list.Add(value);
        }
      }
      return list;
    }

    public static IList EExecuteList(this DmoQuery query)
    {
      using (var session = DmoSession.New())
      {
        return session.ExecuteList(query);
      }
    }

    public static void EExecute(this DQUpdateDom update)
    {
      using (var session = DmoSession.New())
      {
        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }

    public static void EExecute(this DQDeleteDom delete)
    {
      using (var session = DmoSession.New())
      {
        session.ExecuteNonQuery(delete);
        session.Commit();
      }
    }
  }
}
