using ButcherFactory.BO.Utils;
using Forks.EnterpriseServices.DomainObjects2;
using Forks.EnterpriseServices.DomainObjects2.DQuery;
using Forks.EnterpriseServices.SqlDoms;
using Forks.JsonRpc.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TSingSoft.WebPluginFramework;

namespace ButcherFactory.BO.LocalBL
{
  public static class CarcassInStoreBL
  {
    const string RpcPath = @"/MainSystem/B3ClientService/Rpcs/CarcassInStoreRpc/";

    public static CarcassInStore Insert(long? workUnitID, long batchID, decimal weight)
    {
      using (var session = DmoSession.New())
      {
        var entity = new CarcassInStore();
        entity.WorkUnit_ID = workUnitID;
        entity.ProductBatch_ID = batchID;
        entity.UserID = BO.Utils.AppContext.Worker.ID;
        entity.Weight = weight;
        entity.RowIndex = GenerateRowIndex(session, batchID);
        session.Insert(entity);
        session.Commit();
        return entity;
      }
    }

    static int GenerateRowIndex(IDmoSession session, long batchID)
    {
      var query = new DQueryDom(new JoinAlias(typeof(CarcassInStore)));
      query.Columns.Add(DQSelectColumn.Max("RowIndex"));
      query.Where.Conditions.Add(DQCondition.EQ("ProductBatch_ID", batchID));
      return (query.EExecuteScalar<int?>(session) ?? 0) + 1;
    }

    public static void FillCodeAndGoods(long id, string barCode, long goodsID)
    {
      using (var session = DmoSession.New())
      {
        var exist = CheckExist(barCode, session);
        if (exist)
          throw new Exception("条码已使用过");
        var update = new DQUpdateDom(typeof(CarcassInStore));
        update.Where.Conditions.Add(DQCondition.EQ("ID", id));
        update.Columns.Add(new DQUpdateColumn("BarCode", barCode));
        update.Columns.Add(new DQUpdateColumn("Goods_ID", goodsID));
        update.Columns.Add(new DQUpdateColumn("Sync", false));
        update.Columns.Add(new DQUpdateColumn("RowVersion", DQExpression.Add(DQExpression.Field("RowVersion"), DQExpression.Value(1))));
        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }

    public static void ChangeGoods(long id, long goodsID)
    {
      using (var session = DmoSession.New())
      {
        var update = new DQUpdateDom(typeof(CarcassInStore));
        update.Where.Conditions.Add(DQCondition.EQ("ID", id));
        update.Columns.Add(new DQUpdateColumn("Goods_ID", goodsID));
        update.Columns.Add(new DQUpdateColumn("Sync", false));
        update.Columns.Add(new DQUpdateColumn("RowVersion", DQExpression.Add(DQExpression.Field("RowVersion"), DQExpression.Value(1))));
        session.ExecuteNonQuery(update);
        session.Commit();
      }
    }

    static bool CheckExist(string barCode, IDmoSession session)
    {
      if (string.IsNullOrEmpty(barCode))
        return false;
      var query = new DQueryDom(new JoinAlias(typeof(CarcassInStore)));
      query.Columns.Add(DQSelectColumn.Create(DQExpression.Value(1), "c"));
      query.Where.Conditions.Add(DQCondition.EQ("BarCode", barCode));
      return query.EExecuteScalar(session) != null;
    }

    public static BindingList<CarcassInStore> GetLocalDataWithState(bool history)
    {
      var query = new DQueryDom(new JoinAlias(typeof(CarcassInStore)));
      query.Columns.Add(DQSelectColumn.Field("RowIndex"));
      query.Columns.Add(DQSelectColumn.Field("ID"));
      query.Columns.Add(DQSelectColumn.Field("Weight"));
      if (history)
      {
        query.Columns.Add(DQSelectColumn.Field("BarCode"));
        query.Columns.Add(DQSelectColumn.Field("Goods_Name"));
        query.Columns.Add(DQSelectColumn.Field("BeforeWeight"));
        query.Where.Conditions.Add(DQCondition.IsNotNull(DQExpression.Field("Goods_ID")));
        query.Range = SelectRange.Top(30);
      }
      else
        query.Where.Conditions.Add(DQCondition.IsNull(DQExpression.Field("Goods_ID")));
      query.OrderBy.Expressions.Add(DQOrderByExpression.Create("ID", true));
      var result = new BindingList<CarcassInStore>();
      using (var session = DmoSession.New())
      {
        using (var reader = session.ExecuteReader(query))
        {
          while (reader.Read())
          {
            var entity = new CarcassInStore();
            result.Add(entity);
            entity.RowIndex = (int?)reader[0];
            entity.ID = (long)reader[1];
            entity.Weight = (decimal)reader[2];
            if (history)
            {
              entity.BarCode = (string)reader[3];
              entity.Goods_Name = (string)reader[4];
              entity.BeforeWeight = (decimal?)reader[5];
            }
          }
        }
      }
      return result;
    }

    public static List<ExtensionObj> GetBeforeWeight(IEnumerable<string> codeList)
    {
      try
      {
        var json = RpcFacade.Call<string>(RpcPath + "GetWeightInfo", codeList);
        var list = JsonConvert.DeserializeObject<List<ExtensionObj>>(json);
        if (list.Any())
        {
          using (var session = DmoSession.New())
          {
            foreach (var item in list)
              SaveWeightInDB(item, session);
            session.Commit();
          }
        }
        return list;
      }
      catch
      {
#if DEBUG
        throw;
#endif
        return new List<ExtensionObj>();
      }
    }

    static void SaveWeightInDB(ExtensionObj obj, IDmoSession session)
    {
      var update = new DQUpdateDom(typeof(CarcassInStore));
      update.Where.Conditions.Add(DQCondition.EQ("BarCode", obj.StringExt1));
      update.Columns.Add(new DQUpdateColumn("BeforeWeight", obj.DecimalExt1));
      session.ExecuteNonQuery(update);
    }

    public static void UploadCarcassInfo()
    {
      try
      {
        using (var session = DmoSession.New())
        {
          var needUpload = GetUnSyncData(session);
          if (needUpload.Count == 0)
            return;

          var json = JsonConvert.SerializeObject(needUpload);
          RpcFacade.Call<int>(RpcPath + "UploadCarcassInfo", json);
          foreach (var item in needUpload)
            SetLocalAsSyncd(item, session);
          session.Commit();
        }
      }
      catch
      {
#if DEBUG
        throw;
#endif
      }
    }

    static List<CarcassInStoreObj> GetUnSyncData(IDmoSession session)
    {
      var query = new DQueryDom(new JoinAlias("_main", typeof(CarcassInStore)));
      query.Columns.Add(DQSelectColumn.Field("ID"));
      query.Columns.Add(DQSelectColumn.Field("RowVersion"));
      query.Columns.Add(DQSelectColumn.Field("BarCode"));
      query.Columns.Add(DQSelectColumn.Field("UserID"));
      query.Columns.Add(DQSelectColumn.Field("WorkUnit_ID"));
      query.Columns.Add(DQSelectColumn.Field("ProductBatch_ID"));
      query.Columns.Add(DQSelectColumn.Field("Goods_ID"));
      query.Columns.Add(DQSelectColumn.Field("Weight"));
      query.Columns.Add(DQSelectColumn.Field("CreateTime"));
      query.Where.Conditions.Add(DQCondition.And(DQCondition.IsNotNull(DQExpression.Field("Goods_ID")), DQCondition.EQ("Sync", false)));
      query.Range = SelectRange.Top(10);
      query.OrderBy.Expressions.Add(DQOrderByExpression.Create("ID"));

      var upload = new List<CarcassInStoreObj>();
      using (var reader = session.ExecuteReader(query))
      {
        while (reader.Read())
        {
          var obj = new CarcassInStoreObj();
          obj.ID = (long)reader[0];
          obj.RowVersion = (int)reader[1];
          obj.BarCode = (string)reader[2];
          obj.InStoreWorker_ID = (long)reader[3];
          obj.WorkUnit_ID = (long?)reader[4];
          obj.ProductBatch_ID = (long?)reader[5];
          obj.InStoreGoods_ID = (long)reader[6];
          obj.InStoreWeight = (decimal)reader[7];
          obj.InStoreTime = (DateTime)reader[8];
          upload.Add(obj);
        }
      }
      return upload;
    }

    static void SetLocalAsSyncd(CarcassInStoreObj obj, IDmoSession session)
    {
      var update = new DQUpdateDom(typeof(CarcassInStore));
      update.Where.Conditions.Add(DQCondition.And(DQCondition.EQ("ID", obj.ID), DQCondition.EQ("RowVersion", obj.RowVersion)));
      update.Columns.Add(new DQUpdateColumn("Sync", true));
      session.ExecuteNonQuery(update);
    }

    public static void DeleteUnSubmit(long id)
    {
      using (var session = DmoSession.New())
      {
        var delete = new DQDeleteDom(typeof(CarcassInStore));
        delete.Where.Conditions.Add(DQCondition.EQ("ID", id));
        session.ExecuteNonQuery(delete);
        session.Commit();
      }
    }
  }

  class CarcassInStoreObj
  {
    public long ID { get; set; }
    [JsonIgnore]
    public long RowVersion { get; set; }
    public string BarCode { get; set; }
    public long? InStoreWorker_ID { get; set; }
    public long? WorkUnit_ID { get; set; }
    public long? ProductBatch_ID { get; set; }
    public long? InStoreGoods_ID { get; set; }
    public decimal? InStoreWeight { get; set; }
    public DateTime? InStoreTime { get; set; }
  }
}
