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

namespace BO
{
  public class LocalDmoSession
  {
    public static IDmoSessionWithTransaction New()
    {
      return Dmo.NewSession(ButcherAppContext.Context.UrlConfig.OfflineSqlConnection);
    }

    public static bool ConnectionTest()
    {
      using (var session = LocalDmoSession.New())
      {
        try
        {
          var q = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
          q.Columns.Add(DQSelectColumn.Create(DQExpression.Value(1), "c"));
          q.Range = SelectRange.Top(1);
          session.ExecuteScalar(q);
          return true;
        }
        catch
        {
          return false;
        }
      }
    }
    /// <summary>
    /// 新增
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="detail"></param>
    public static void Insert<T>(T detail) where T : LocalSyncBase
    {
      using (var session = LocalDmoSession.New())
      {
        if (detail.ID != 0)
          throw new Exception("Insert时要保证ID不为0");
        session.Insert(detail);
        session.Commit();
      }
    }

    /// <summary>
    /// 同步修改到服务器之后调用
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="id"></param>
    /// <param name="serviceid"></param>
    public static void UpdateAfterInsertSynced<T>(long id, long serviceid) where T : LocalSyncBase
    {
      var updateDom = new DQUpdateDom(typeof(T));
      updateDom.Where.Conditions.Add(DQCondition.EQ("ID", id));
      updateDom.Columns.Add(new DQUpdateColumn("IsSynced", true));
      updateDom.Columns.Add(new DQUpdateColumn("SyncTime", DateTime.Now));
      updateDom.Columns.Add(new DQUpdateColumn("Service_ID", serviceid));

      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }

    /// <summary>
    /// 同步更改到服务器之后调用
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="id"></param>
    public static void UpdateAfterUpdateSynced<T>(long id) where T : LocalSyncBase
    {
      var updateDom = new DQUpdateDom(typeof(T));
      updateDom.Where.Conditions.Add(DQCondition.EQ("ID", id));
      updateDom.Columns.Add(new DQUpdateColumn("WillBeUpdated", false));
      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }
    
    /// <summary>
    /// 同步删除到服务器之后调用
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="id"></param>
    public static void UpdateAfterDeleteSynced<T>(long id) where T : LocalSyncBase
    {
      var updateDom = new DQUpdateDom(typeof(T));
      updateDom.Where.Conditions.Add(DQCondition.EQ("ID", id));
      updateDom.Columns.Add(new DQUpdateColumn("WillBeDeleted", false));
      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }

    /// <summary>
    /// 置删除标记 不是真正的删除
    /// </summary>
    /// <param name="id"></param>
    public static void SaveDelete<T>(long id) where T : LocalSyncBase
    {
      var updateDom = new DQUpdateDom(typeof(T));
      updateDom.Where.Conditions.Add(DQCondition.EQ("ID", id));
      updateDom.Columns.Add(new DQUpdateColumn("IsDeleted", true));
      updateDom.Columns.Add(new DQUpdateColumn("WillBeDeleted", true));
      updateDom.Columns.Add(new DQUpdateColumn("DeleteTime", DateTime.Now));
      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }

    public static void Update<T>(T detail, params string[] properties) where T : LocalSyncBase
    {
      var type = typeof(T);
      using (var session = LocalDmoSession.New())
      {
        if (detail.ID == 0)
          throw new Exception("Update时要保证ID不能为0");
        if (properties.Contains("ID"))
          throw new Exception("ID不能通过该方法维护");
        if (properties.Length == 0)
          throw new Exception("Update时要给出属性数组");
        var update = new DQUpdateDom(type);
        update.Where.Conditions.Add(DQCondition.EQ("ID", detail.ID));
        foreach (var p in properties)
        {
          //          if (p == "Sync" && detail.Sync)
          //            detail.Sync = false;
          update.Columns.Add(new DQUpdateColumn(p, type.GetProperty(p).GetValue(detail)));
        }
        update.Columns.Add(new DQUpdateColumn("WillBeUpdated", true));
        
        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }


    /// <summary>
    /// 根据条件获取获取没有被删除的集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static BindingList<T> GetNotDeleteListByDate<T>(DateTime date) where T : LocalSyncBase
    {
      List<T> list;
      DateTime minDate = date.Date;
      DateTime maxDate = date.Date.AddDays(1);
      var query = new DmoQuery(typeof(T));
      query.Where.Conditions.Add(DQCondition.GreaterThanOrEqual("CreateTime", minDate));
      query.Where.Conditions.Add(DQCondition.LessThan("CreateTime", maxDate));
      query.Where.Conditions.Add(DQCondition.EQ("IsDeleted", false));
      using (var session = LocalDmoSession.New())
      {
        list = session.ExecuteList(query).Cast<T>().ToList();
      }
      var bindingList = new BindingList<T>();
      foreach (T t in list)
      {
        bindingList.Add(t);
      }
      return bindingList;
    }


    /// <summary>
    /// 根据条件获取获取没有被删除的集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static BindingList<T> GetNotDeleteList<T>(Dictionary<string, string> eqdic, int? top) where T : LocalSyncBase
    {
      List<T> list;
      var query = new DmoQuery(typeof(T));
      if (top.HasValue)
      {
        query.Range = SelectRange.Top(top.Value);
      }
      query.OrderBy.Expressions.Add(DQOrderByExpression.Create("ID", true));

      if (eqdic != null)
      {
        foreach (KeyValuePair<string, string> pair in eqdic)
        {
          query.Where.Conditions.Add(DQCondition.EQ(pair.Value, pair.Value));
        }
      }

      query.Where.Conditions.Add(DQCondition.EQ("IsDeleted", false));
      using (var session = LocalDmoSession.New())
      {
        list = session.ExecuteList(query).Cast<T>().ToList();
      }

      var bindingList = new BindingList<T>();
      foreach (T t in list)
      {
        bindingList.Add(t);
      }
      return bindingList;
    }

    /// <summary>
    /// 获取需要同步的数据 默认一次50条
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static LocalForSyncList<T> GetNeedSyncList<T>(int top = 50) where T : LocalSyncBase
    {
      var result = new LocalForSyncList<T>();

      var query = new DmoQuery(typeof(T));
      var 没同步 = DQCondition.EQ("IsSynced", false);
      var 已同步将要删除或者将要修改 = DQCondition.And(DQCondition.EQ("IsSynced", true), DQCondition.Or(DQCondition.EQ("WillBeDeleted", true), DQCondition.EQ("WillBeUpdated", true)));

      query.Where.Conditions.Add(DQCondition.Or(没同步, 已同步将要删除或者将要修改));
      query.Range = SelectRange.Top(top);
      query.Where.Conditions.Add(DQCondition.EQ("IsDeleted", false));

      List<T> list;
      using (var session = LocalDmoSession.New())
      {
        list = session.ExecuteList(query).Cast<T>().ToList();
      }

      var willInsertList = new List<T>();
      var willUpdateList = new List<T>();
      var willDeleteList = new List<T>();
      foreach (T t in list)
      {
        if (!t.IsSynced)
        {
          //没同步的插入
          willInsertList.Add(t);
        }
        else
        {
          //如果已同步
          if (t.WillBeDeleted)
          {
            //如果要删除

            willDeleteList.Add(t);
          }
          else
          {
            //已同步 如果没删除 要更新
            willUpdateList.Add(t);

          }
        }
      }

      result.WillInsertList = willInsertList;
      result.WillUpdateList = willUpdateList;
      result.WillDeleteList = willDeleteList;

      return result;
    }
  }
}
