using BO.BO.BaseInfo;
using BO.BO.Bill;
using Forks.EnterpriseServices.DomainObjects2;
using Forks.EnterpriseServices.DomainObjects2.DQuery;
using Forks.EnterpriseServices.SqlDoms;
using Forks.JsonRpc.Client;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using TSingSoft.WebPluginFramework;

namespace BO.Utils.BillRpc
{
  public static class GradeAndWeightRpc
  {
    static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public static List<GradeAndWeight> GetGradeAndWeightList(DateTime date, bool isTang)
    {
      const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/GetGradeAndWeightList";
      var result = RpcFacade.Call<string>(method, date, isTang);
      var list = serializer.Deserialize<List<GradeAndWeight>>(result);
      short type = 1;
      if (isTang)
        type = 0;
      var sum = GetSumNumber(date, type);
      foreach (var item in list)
      {
        var first = sum.FirstOrDefault(x => x.Item1 == item.Order);
        if (first != null)
          item.Already = first.Item2;
      }
      return list;
    }

    static List<Tuple<int, int>> GetSumNumber(DateTime date, short type)
    {
      var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date), DQCondition.EQ("Technics", type), DQCondition.IsNotNull(DQExpression.Field("Order"))));
      query.Columns.Add(DQSelectColumn.Field("Order"));
      query.Columns.Add(DQSelectColumn.Count());
      query.GroupBy.Expressions.Add(DQExpression.Field("Order"));
      var list = new List<Tuple<int, int>>();
      using (var session = LocalDmoSession.New())
      {
        using (var reader = session.ExecuteReader(query))
        {
          while (reader.Read())
            list.Add(new Tuple<int, int>((int)reader[0], Convert.ToInt32(reader[1])));
        }
        return list;
      }
    }

    public static void SetGradeFinish(long orderDetailID, short technics)
    {
      const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/SetGradeFinish";
      RpcFacade.Call<int>(method, orderDetailID, technics);
    }

    public static List<BodyDiscontItem> GetBodyDiscontItem()
    {
      const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/GetBodyDiscontItemSetting";
      var json = RpcFacade.Call<string>(method);
      return serializer.Deserialize<List<BodyDiscontItem>>(json);
    }

    public static void SaveBodyDiscontItem(List<CTuple<long, decimal?>> list)
    {
      const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/SaveBodyDiscontItemSetting";
      RpcFacade.Call<int>(method, serializer.Serialize(list));
    }

    public static List<DataConfirmList> GetDataConfirmList(DateTime date, int? order)
    {
      const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/GetDataConfirmList";
      var result = RpcFacade.Call<string>(method, date, order);
      return serializer.Deserialize<List<DataConfirmList>>(result);
    }
  }

  public static class LocalGradeAndWeightBL
  {
    static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public static void ClearWeightBySID(long sid)
    {
      var updateDom = new DQUpdateDom(typeof(GradeAndWeight_Detail));
      updateDom.Where.Conditions.Add(DQCondition.EQ("SID", sid));
      updateDom.Columns.Add(new DQUpdateColumn("Weight", DQExpression.NULL));
      updateDom.Columns.Add(new DQUpdateColumn("Sync", false));
      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }

    public static void DeleteBySID(long sid)
    {
      var updateDom = new DQUpdateDom(typeof(GradeAndWeight_Detail));
      updateDom.Where.Conditions.Add(DQCondition.EQ("SID", sid));
      updateDom.Columns.Add(new DQUpdateColumn("IsDeleted", true));
      updateDom.Columns.Add(new DQUpdateColumn("Sync", false));
      using (var session = LocalDmoSession.New())
      {
        session.ExecuteNonQuery(updateDom);
        session.Commit();
      }
    }

    public static void UpdateLosted(long sid)
    {
      var updateDom = new DQUpdateDom(typeof(GradeAndWeight_Detail));
      updateDom.Where.Conditions.Add(DQCondition.EQ("SID", sid));
      updateDom.Columns.Add(new DQUpdateColumn("IsLostWeight", true));

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

    public static BindingList<GradeAndWeight_Detail> GetDetails(DateTime date, int top = 15)
    {
      var bindList = new BindingList<GradeAndWeight_Detail>();
      //      var bindList=new BlockingCollection<GradeAndWeight_Detail>();
      var list = new List<GradeAndWeight_Detail>();

      var query = new DmoQuery(typeof(GradeAndWeight_Detail));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date)));
      query.OrderBy.Expressions.Add(DQOrderByExpression.Create("Index", true));
      query.Range = SelectRange.Top(top);
      using (var session = LocalDmoSession.New())
      {
        list = session.ExecuteList(query).Cast<GradeAndWeight_Detail>().ToList();
      }
      foreach (GradeAndWeight_Detail detail in list)
      {
        bindList.Add(detail);
      }
      return bindList;
    }

    public static int GetSumNumber(DateTime date, short type)
    {
      var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Technics", type), DQCondition.EQ("Date", date)));
      query.Columns.Add(DQSelectColumn.Count());
      using (var session = LocalDmoSession.New())
      {
        return Convert.ToInt32(session.ExecuteScalar(query));
      }
    }

    //public static int GetSumNumber(long orderID, short type)
    //{
    //  var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
    //  query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Technics", type), DQCondition.EQ("OrderDetail_ID", orderID)));
    //  query.Columns.Add(DQSelectColumn.Count());
    //  using (var session = LocalDmoSession.New())
    //  {
    //    return Convert.ToInt32(session.ExecuteScalar(query));
    //  }
    //}

    public static List<Tuple<short, int>> GetSumNumber(DateTime date, int? order)
    {
      var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date)));
      if (order.HasValue)
        query.Where.Conditions.Add(DQCondition.EQ("Order", order));
      query.Columns.Add(DQSelectColumn.Field("Technics"));
      query.Columns.Add(DQSelectColumn.Count());
      query.GroupBy.Expressions.Add(DQExpression.Field("Technics"));
      var list = new List<Tuple<short, int>>();
      using (var session = LocalDmoSession.New())
      {
        using (var reader = session.ExecuteReader(query))
        {
          while (reader.Read())
            list.Add(new Tuple<short, int>((short)reader[0], Convert.ToInt32(reader[1])));
        }
        return list;
      }
    }

    public static decimal GetSumWeight(DateTime date)
    {
      var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date)));

      query.Columns.Add(DQSelectColumn.Sum("Weight"));
      using (var session = LocalDmoSession.New())
      {
        return Convert.ToDecimal(session.ExecuteScalar(query));
      }
    }

    public static List<GradeAndWeight_Detail> GetLostWeightDetails(DateTime date)
    {
      var query = new DmoQuery(typeof(GradeAndWeight_Detail));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("IsLostWeight", true), DQCondition.EQ("Date", date)));
      query.OrderBy.Expressions.Add(DQOrderByExpression.Create("Index", true));

      using (var session = LocalDmoSession.New())
      {
        return session.ExecuteList(query).Cast<GradeAndWeight_Detail>().ToList();
      }
    }

    public static void Insert(GradeAndWeight_Detail detail)
    {
      using (var session = LocalDmoSession.New())
      {
        if (detail.SID != 0)
          throw new Exception("Insert时要保证SID不为0");
        session.Insert(detail);
        session.Commit();
      }
    }

    public static void Update(GradeAndWeight_Detail detail, params string[] properties)
    {
      var type = typeof(GradeAndWeight_Detail);
      using (var session = LocalDmoSession.New())
      {
        if (detail.SID == 0)
          throw new Exception("Update时要保证SID不能为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("SID", detail.SID));
        foreach (var p in properties)
        {
          //        if (p == "Sync" && detail.Sync)
          //          detail.Sync = false;
          update.Columns.Add(new DQUpdateColumn(p, type.GetProperty(p).GetValue(detail)));
        }

        //只要修改就设置 Sync为False
        update.Columns.Add(new DQUpdateColumn("Sync", false));

        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }

    public static void Update(GradeAndWeight_Detail detail, GradeAndWeight dmo)
    {
      if (dmo == null)
      {
        throw new Exception(string.Format("请选择左侧的{0}顺序", detail.Technics_Name));
      }
      detail.Order = dmo.Order;
      detail.OrderDetail_ID = dmo.OrderDetail_ID;
      Update(detail, "OrderDetail_ID", "Order", "Livestock_ID", "Livestock_Name", "Technics", "Technics_Name");
    }

    public static void Sync()
    {
      ClearUnSyncDelete();
      var syncs = GetAllNeedSyncDetails();
      foreach (var detail in syncs)
      {
        const string method = "/MainSystem/B3ClientService/Rpcs/BillRpc/GradeAndWeightRpc/UpdateOrInsertDetailOrDelete";
        var id = RpcFacade.Call<long>(method, serializer.Serialize(detail));
        if (detail.IsDeleted)
          Delete(detail.SID);
        else
          SetDetailSynced(detail, id);
      }
    }

    static void ClearUnSyncDelete()
    {
      using (var session = LocalDmoSession.New())
      {
        var delete = new DQDeleteDom(typeof(GradeAndWeight_Detail));
        delete.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", true), DQCondition.EQ("ID", 0)));
        session.ExecuteNonQuery(delete);
        session.Commit();
      }
    }

    static void Delete(long sid)
    {
      using (var session = LocalDmoSession.New())
      {
        var delete = new DQDeleteDom(typeof(GradeAndWeight_Detail));
        delete.Where.Conditions.Add(DQCondition.EQ("SID", sid));
        session.ExecuteNonQuery(delete);
        session.Commit();
      }
    }

    static IEnumerable<GradeAndWeight_Detail> GetAllNeedSyncDetails()
    {
      using (var session = LocalDmoSession.New())
      {
        var query = new DmoQuery(typeof(GradeAndWeight_Detail));
        query.OrderBy.Expressions.Add(DQOrderByExpression.Create("SID"));
        query.Range = SelectRange.Top(50);
        query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("Sync", false),
          DQCondition.IsNotNull(DQExpression.Field("Technics"))));
        return session.ExecuteList(query).Cast<GradeAndWeight_Detail>();
      }
    }

    static void SetDetailSynced(GradeAndWeight_Detail detail, long id)
    {
      using (var session = LocalDmoSession.New())
      {
        var update = new DQUpdateDom(typeof(GradeAndWeight_Detail));
        update.Columns.Add(new DQUpdateColumn("Sync", true));
        if (detail.ID == 0)
        {
          detail.ID = id;
          update.Columns.Add(new DQUpdateColumn("ID", id));
        }
        update.Where.Conditions.Add(DQCondition.EQ("SID", detail.SID));
        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }

    public static void SaveWeightData(decimal weight)
    {
      using (var session = LocalDmoSession.New())
      {
        var record = new WeightData { Weight = weight, Time = DateTime.Now };
        session.Insert(record);
        session.Commit();
      }
    }

    public static int GetTodayTotalCount(DateTime date)
    {
      var query = new DQueryDom(new JoinAlias(typeof(GradeAndWeight_Detail)));
      query.Columns.Add(DQSelectColumn.Count());
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date)));
      using (var session = LocalDmoSession.New())
      {
        return Convert.ToInt32(session.ExecuteScalar(query));
      }
    }

    public static List<GradeAndWeight_Detail> GetGradeAndWeightDetails(DateTime date, int? order, int? index)
    {
      var query = new DmoQuery(typeof(GradeAndWeight_Detail));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("IsDeleted", false), DQCondition.EQ("Date", date)));
      if (order.HasValue)
        query.Where.Conditions.Add(DQCondition.Or(DQCondition.IsNull(DQExpression.Field("Order")), DQCondition.EQ("Order", order)));
      if (index.HasValue)
        query.Where.Conditions.Add(DQCondition.EQ("Index", index));
      using (var session = LocalDmoSession.New())
      {
        return session.ExecuteList(query).Cast<GradeAndWeight_Detail>().ToList();
      }
    }

    public static void InsertOrUpdate(GradeAndWeight_Detail entity)
    {
      using (var session = LocalDmoSession.New())
      {
        if (entity.Technics_Name == "烫褪")
          entity.Technics = 0;
        else
          entity.Technics = 1;

        if (entity.SID == 0)
        {
          session.Insert(entity);
        }
        else
        {
          entity.Sync = false;
          session.Update(entity);
        }
        session.Commit();
      }
    }
  }
}
