using AutoMapper;
using APT.BaseData.Domain.Entities;
using APT.BaseData.Domain.Entities;
using APT.BaseData.Domain.Enums;
using APT.BaseData.Domain.IServices;
using APT.BaseData.Domain.Msg;
using APT.Infrastructure.Core;
using APT.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using APT.Infrastructure.Api;
namespace APT.BaseData.Services.DomainServices
{
    public partial class PFCodeRuleSerialService : CommonService, IPFCodeRuleSerialService
    {
        public PFCodeRuleSerialService(IRepository repository)
            : base(repository)
        {
        }
        /// <summary>
        /// 跑批
        /// </summary>
        /// <returns></returns>
        public bool RunBatch()
        {
            //增加跑批日志表
            var logs = this.GetEntities<T_PF_CODE_RULE_RUN_LOG>(i => i.IS_COMPLETE == false);
            if (logs.Any())
            {
                foreach (var l in logs)
                {
                    if (l.START_TIME <= DateTime.Now.AddHours(-6))
                    {
                        l.IS_COMPLETE = true;
                    }
                }
                this.BantchUpdateEntity(logs);
                //如果有未完成的跑批数据不继续跑批，如超过6个小时，则认为是异常中断
                if (logs.Any(i => i.START_TIME > DateTime.Now.AddHours(-6)))
                {
                    return false;
                }
            }
            //开始跑批
            const int Day = -2;
            var date = DateTime.Now.ToString("yyyyMMdd");
            var nextDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd");
            var codeRules = this.GetEntities<T_PF_CODE_RULE>(i => i.ENABLE_STATUS == (int)FMEnableStatusEnum.启用,
                    new BaseFilter(), new string[] { "Nav_Org" }).ToList();
            if (codeRules.Any())
            {
                //跑批日志表增加一条数据
                var log = new T_PF_CODE_RULE_RUN_LOG
                {
                    ID = Guid.NewGuid(),
                    CREATE_TIME = DateTime.Now,
                    START_TIME = DateTime.Now,
                    IS_COMPLETE = false,
                    ORG_ID = codeRules.FirstOrDefault().ORG_ID
                };
                this.AddEntity(log);
                try
                {
                    //var dbCodeRuleSerials=this.GetEntities<T_PF_CODE_RULE_SERIAL>(t => t.STATUS == (int)PFCodeRuleStatus.未用).ToList(); 
                    List<T_PF_CODE_RULE_SERIAL> codeRuleSerials = new List<T_PF_CODE_RULE_SERIAL>();
                    foreach (var rule in codeRules)
                    {
                        DoGenSerialByRule(rule, date, codeRuleSerials);
                    }
                    //预生成第二天的编码    因为工厂通常有夜班  编码未必可以及时生成
                    foreach (var rule in codeRules)
                    {
                        DoGenSerialByRule(rule, nextDate, codeRuleSerials);
                    }
                    this.BantchAddEntity(codeRuleSerials);

                    var towDay = DateTime.Now.AddDays(Day).ToString("yyyyMMdd");
                    var serialLogs = this.GetEntities<T_PF_CODE_RULE_SERIAL>(i => i.DATE_VALUE != null
                   && string.Compare(i.DATE_VALUE, towDay) <= 0, true).ToList();
                    if (serialLogs.Any())
                    {
                        var seialAddLogs = new List<T_PF_CODE_RULE_SERIAL>();
                        foreach (var s in serialLogs)
                        {
                            seialAddLogs.Add(s);
                            if (seialAddLogs.Count >= 10000)
                            {
                                AddLogByInValidSerial(seialAddLogs);
                                seialAddLogs.Clear();
                            }
                        }
                        AddLogByInValidSerial(seialAddLogs);
                    }
                }
                finally
                {
                    var oldLog = this.GetEntity<T_PF_CODE_RULE_RUN_LOG>(log.ID.ToString());
                    if (oldLog != null)
                    {
                        oldLog.END_TIME = DateTime.Now;
                        oldLog.IS_COMPLETE = true;
                        this.UpdateEntity(oldLog);
                    }
                }

            }

            return true;
        }

        private void AddLogByInValidSerial(List<T_PF_CODE_RULE_SERIAL> list)
        {
            if (list == null || !list.Any()) return;
            this.DeleteEntity<T_PF_CODE_RULE_SERIAL>(list);
            //var seialAddLogs = new List<T_PF_CODE_RULE_SERIAL_LOG>();
            //foreach (var s in list)
            //{
            //             var log = new T_PF_CODE_RULE_SERIAL_LOG();//  Mapper.Map<T_PF_CODE_RULE_SERIAL, T_PF_CODE_RULE_SERIAL_LOG>(s); 
            //             log.ORG_ID = log.ORG_ID;
            //             CopyUtils.CopyObject(log, s);
            //             seialAddLogs.Add(log); 
            //}
            //this.BantchAddEntity(seialAddLogs);
        }

        private void DoGenSerialByRule(T_PF_CODE_RULE rule, string date, List<T_PF_CODE_RULE_SERIAL> codeRuleSerials)
        {
            Expression<Func<T_PF_CODE_RULE_SERIAL, bool>> expression = t => t.ORG_ID == rule.ORG_ID
                      && t.CODE_TYPE == rule.CODE_TYPE;
            if (!rule.IS_IGNORE_DATE.HasValue || !rule.IS_IGNORE_DATE.Value)
                expression = expression.And(t => t.DATE_VALUE == date);
            var pageFilter = new BasePageFilter(1, 1);
            pageFilter.Sort = "NUM";
            pageFilter.Order = DbOrder.DESC;
            var maxDbCodeRuleSerial = this.GetOrderPageEntities<T_PF_CODE_RULE_SERIAL>(expression, pageFilter);
            int num = 0;
            T_PF_CODE_RULE_SERIAL maxCodeRuleSerail = null;
            if (maxDbCodeRuleSerial.Items.Any())
            {
                maxCodeRuleSerail = maxDbCodeRuleSerial.Items.FirstOrDefault();
                if (maxCodeRuleSerail != null)
                    num = maxCodeRuleSerail.NUM;
            }
            num++;

            Expression<Func<T_PF_CODE_RULE_SERIAL, bool>> expression1 = t => t.ORG_ID == rule.ORG_ID
                      && t.CODE_TYPE == rule.CODE_TYPE && t.STATUS == (int)PFCodeRuleStatus.未用;
            if (!rule.IS_IGNORE_DATE.HasValue || !rule.IS_IGNORE_DATE.Value)
                expression1 = expression1.And(t => t.DATE_VALUE == date);

            var minUnUseSerial = this.GetEntity<T_PF_CODE_RULE_SERIAL>(expression1, new BaseFilter()
            {
                Order = DbOrder.ASC,
                Sort = "NUM"
            });
            int minUnUseNum = 0;
            if (minUnUseSerial != null)
                minUnUseNum = minUnUseSerial.NUM - 1;
            else if (maxCodeRuleSerail != null && maxCodeRuleSerail.STATUS != (int)PFCodeRuleStatus.未用)
                minUnUseNum = maxCodeRuleSerail.NUM;

            var maxQty = rule.QTY == null || rule.QTY == 0 ? 100 : rule.QTY;
            maxQty += minUnUseNum;
            var serial = new T_PF_CODE_RULE_SERIAL
            {
                ORG_ID = rule.ORG_ID,
                CODE_TYPE = rule.CODE_TYPE,
                DATE_VALUE = rule.IS_IGNORE_DATE.HasValue && rule.IS_IGNORE_DATE.Value ? null : date,
                STATUS = (int)PFCodeRuleStatus.未用
            };
            //位数限制
            var ruleMaxQty = Math.Floor(Math.Pow(10, rule.SERIAL_NUM_LEN) - 1);
            if (maxQty > (int)ruleMaxQty)
                maxQty = (int)ruleMaxQty;

            for (int i = num; i <= maxQty; i++)
            {
                var cpSerial = (T_PF_CODE_RULE_SERIAL)serial.Clone();
                cpSerial.ID = Guid.NewGuid();
                cpSerial.NUM = i;
                cpSerial.SERIAL = string.Concat(rule.CODE_PREFIX,
                    (rule.Nav_Org == null ? string.Empty : (rule.Nav_Org.CODE)),
                    (rule.IS_IGNORE_DATE.HasValue && rule.IS_IGNORE_DATE.Value ? string.Empty : date),
                    i.ToString().PadLeft(rule.SERIAL_NUM_LEN, '0'));
                codeRuleSerials.Add(cpSerial);
                if (codeRuleSerials.Count >= 1000)
                {
                    this.BantchAddEntity(codeRuleSerials);
                    codeRuleSerials.Clear();
                }
            }
        }

        /// <summary>
        /// 手动触发
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public bool GenSerial(KeywordFilter filter)
        {
            var date = DateTime.Now.ToString("yyyyMMdd");
            var type = int.Parse(filter.Keyword);
            filter.Sort = string.Empty;
            var codeRule = this.GetEntity<T_PF_CODE_RULE>(i => i.CODE_TYPE == type, filter, new string[] { "Nav_Org" });

            if (codeRule == null)
                throw new Exception(ErrMsg.PF_ERR_CODE_RULE_TYPE + ":" + type);

            List<T_PF_CODE_RULE_SERIAL> codeRuleSerials = new List<T_PF_CODE_RULE_SERIAL>();
            DoGenSerialByRule(codeRule, date, codeRuleSerials);
            this.BantchAddEntity(codeRuleSerials);

            return true;
        }

        /// <summary>
        /// 检验预取流水
        /// </summary>
        /// <returns></returns>
        public bool SerialCheck()
        {
            var checkSerial = this.GetEntities<T_PF_CODE_RULE_SERIAL>(i => i.STATUS == (int)PFCodeRuleStatus.预取
            && i.RELEASE_TIME != null && i.RELEASE_TIME < DateTime.Now).ToList();
            if (checkSerial.Any())
            {
                checkSerial.ForEach(i =>
                {
                    i.STATUS = (int)PFCodeRuleStatus.未用;
                    i.TAKE_TIME = null; i.RELEASE_TIME = null;
                });
                //commit
                //1.初始化当前的数据
                this.BantchUpdateEntity(checkSerial);
            }
            return true;
        }

    }
}
