using MongoDB.Driver.Linq;
using Tiobon.Core.Model.Models.RootTkey.Interface;
using static Tiobon.Core.Model.Consts;

namespace Tiobon.Core.Services;

/// <summary>
/// 必选修规则 (服务)
/// </summary>
public class Ghre_StudyRuleServices : BaseServices<Ghre_StudyRule, Ghre_StudyRuleDto, InsertGhre_StudyRuleInput, EditGhre_StudyRuleInput>, IGhre_StudyRuleServices
{
    private readonly IBaseRepository<Ghre_StudyRule> _dal;
    private readonly IGhre_CourseServices _ghre_CourseServices;
    private readonly IGhre_CourseSceneServices _ghre_CourseSceneServices;
    private readonly IGhre_StudyRuleStaffServices _ghre_StudyRuleStaffServices;
    public Ghre_StudyRuleServices(ICaching caching,
        IGhre_CourseServices ghre_CourseServices,
        IGhre_CourseSceneServices ghre_CourseSceneServices,
        IGhre_StudyRuleStaffServices ghre_StudyRuleStaffServices,
        IBaseRepository<Ghre_StudyRule> dal)
    {
        this._dal = dal;
        base.BaseDal = dal;
        base._caching = caching;
        _ghre_CourseServices = ghre_CourseServices;
        _ghre_CourseSceneServices = ghre_CourseSceneServices;
        _ghre_StudyRuleStaffServices = ghre_StudyRuleStaffServices;
    }

    public override async Task<ServicePageResult<Ghre_StudyRuleDto>> QueryFilterPage(QueryBody filter, string condition, bool? IsEnable = true)
    {
        if (string.IsNullOrWhiteSpace(filter.orderBy))
            filter.orderBy = "CreateTime1 DESC";

        if (filter.pageSize == 0)
            filter.pageSize = 10000;

        var countSql = @$" SELECT COUNT(1) FROM  Ghre_StudyRule_v A";
        var sql = @$" SELECT *
                    FROM Ghre_StudyRule_v A";

        string conditions = " WHERE 1=1 ";
        conditions += $" AND dbo.FUserDataBelongPriv ({App.User.ID}, A.DataBelongID, NULL) = 1";

        if (IsEnable == true)
            conditions += " AND IsEnable = 1";
        else if (IsEnable == false)
            conditions += " AND IsEnable = 0";

        if (!string.IsNullOrWhiteSpace(condition))
            conditions += " AND " + condition;


        if (filter.jsonParam != null)
            foreach (JProperty jProperty in filter.jsonParam.Properties())
            {
                var name = jProperty.Name;
                var value = jProperty.Value.ToString();
                if (name == "page" || name == "pageSize")
                    continue;
                if (name == "StaffId")
                {

                    var jsonParam = JsonHelper.JsonToObj<JsonParam>(value);
                    var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());
                    if (ids1 is null)
                        continue;
                    string sql1 = $"SELECT DISTINCT B.Id from Ghre_StudyRuleStaff A join Ghre_StudyRule B ON A.StudyRuleId = B.ID WHERE B.IsEnable=1 AND A.StaffId IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))})";
                    ids1 = await Db.Ado.SqlQueryAsync<string>(sql1);
                    switch (jsonParam.operationKey)
                    {
                        case "EqualAny"://  
                            conditions += $"  AND  Id IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))})";
                            break;
                        case "NotEqualAny"://  
                            conditions += $" AND Id NOT IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))})";

                            break;
                        default:
                            break;
                    }

                    continue;
                }
                if (!string.IsNullOrWhiteSpace(value))
                    conditions = DealConditions(conditions, name, value);
            }

        sql += conditions;
        countSql += conditions;
        int total = await Db.Ado.GetIntAsync(countSql);

        sql = "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY " + filter.orderBy + ") NUM FROM (SELECT * FROM (" + sql + " ";
        sql += ") A ) B ) C";

        sql += " WHERE NUM <= " + filter.pageNum * filter.pageSize + " AND NUM >" + (filter.pageNum - 1) * filter.pageSize;

        var entitys = await Db.Ado.SqlQueryAsync<Ghre_StudyRuleDto>(sql);

        var ids = entitys.Select(x => x.Id).ToList();
        var staffs = await _ghre_StudyRuleStaffServices.Query(x => x.StudyRuleId != null && ids.Contains(x.StudyRuleId.Value));

        var zoneIds = new List<int?>();
        var deptIds = new List<int?>();
        var titleIds = new List<int?>();
        var gradeIds = new List<int?>();
        var jobIds = new List<int?>();
        entitys.ForEach(async rule =>
        {
            rule.StaffNames = string.Join(",", staffs.Where(o => o.StudyRuleId == rule.Id).Select(o => o.StaffName));
            rule.DataBelongName = await GetDataBelongName(rule.DataBelongID);

            if (!rule.ZoneId.IsNull())
                rule.ZoneIds = JsonHelper.JsonToObj<List<int?>>(rule.ZoneId);
            if (!rule.DeptId.IsNull())
                rule.DeptIds = JsonHelper.JsonToObj<List<int?>>(rule.DeptId);
            if (!rule.TitleId.IsNull())
                rule.TitleIds = JsonHelper.JsonToObj<List<int?>>(rule.TitleId);
            if (!rule.GradeId.IsNull())
                rule.GradeIds = JsonHelper.JsonToObj<List<int?>>(rule.GradeId);
            if (!rule.JobId.IsNull())
                rule.JobIds = JsonHelper.JsonToObj<List<int?>>(rule.JobId);

            if (rule.ZoneIds.Any())
                zoneIds.AddRange(rule.ZoneIds);

            if (rule.DeptIds.Any())
                deptIds.AddRange(rule.DeptIds);

            if (rule.TitleIds.Any())
                titleIds.AddRange(rule.TitleIds);

            if (rule.GradeIds.Any())
                gradeIds.AddRange(rule.GradeIds);

            if (rule.JobIds.Any())
                jobIds.AddRange(rule.JobIds);
        });
        if (zoneIds.Any())
        {
            var zones = await Db.Queryable<Ghra_Zone>().Where(x => zoneIds.Contains(x.ZoneID)).ToListAsync();

            entitys.ForEach(rule =>
            {
                rule.ZoneName = string.Join(",", zones.Where(o => rule.ZoneIds.Contains(o.ZoneID)).Select(o => o.ZoneName));
            });
        }

        if (deptIds.Any())
        {
            var depts = await Db.Queryable<Ghro_Dept>().Where(x => deptIds.Contains(x.DeptID)).ToListAsync();

            entitys.ForEach(rule =>
            {
                rule.DeptName = string.Join(",", depts.Where(o => rule.DeptIds.Contains(o.DeptID)).Select(o => o.DeptName));
            });
        }

        if (titleIds.Any())
        {
            var titles = await Db.Queryable<Ghra_Title>().Where(x => titleIds.Contains(x.TitleID)).ToListAsync();

            entitys.ForEach(rule =>
            {
                rule.TitleName = string.Join(",", titles.Where(o => rule.TitleIds.Contains(o.TitleID)).Select(o => o.TitleName));
            });
        }

        if (gradeIds.Any())
        {
            var grades = await Db.Queryable<Ghra_Grade>().Where(x => gradeIds.Contains(x.GradeID)).ToListAsync();

            entitys.ForEach(rule =>
            {
                rule.GradeName = string.Join(",", grades.Where(o => rule.GradeIds.Contains(o.GradeID)).Select(o => o.GradeName));
            });
        }

        if (jobIds.Any())
        {
            var jobs = await Db.Queryable<Ghra_Job>().Where(x => jobIds.Contains(x.JobID)).ToListAsync();

            entitys.ForEach(rule =>
            {
                rule.JobName = string.Join(",", jobs.Where(o => rule.JobIds.Contains(o.JobID)).Select(o => o.JobName));
            });
        }


        return new ServicePageResult<Ghre_StudyRuleDto>(filter.pageNum, total, filter.pageSize, entitys);

    }


    public override async Task<long> Add(InsertGhre_StudyRuleInput entity)
    {

        if (!entity.ZoneIds.IsNull() && entity.ZoneIds.Any())
            entity.ZoneId = JsonHelper.ObjToJson(entity.ZoneIds);
        if (!entity.DeptIds.IsNull() && entity.DeptIds.Any())
            entity.DeptId = JsonHelper.ObjToJson(entity.DeptIds);
        if (!entity.TitleIds.IsNull() && entity.TitleIds.Any())
            entity.TitleId = JsonHelper.ObjToJson(entity.TitleIds);
        if (!entity.GradeIds.IsNull() && entity.GradeIds.Any())
            entity.GradeId = JsonHelper.ObjToJson(entity.GradeIds);
        if (!entity.JobIds.IsNull() && entity.JobIds.Any())
            entity.JobId = JsonHelper.ObjToJson(entity.JobIds);

        var companyCode = await QueryCompanyCode();
        if (companyCode != "Viavi")
            if (entity.TrainType == "NewStaff")
            {
                if (!entity.ZoneIds.Any() &&
                    !entity.DeptIds.Any() &&
                    !entity.TitleIds.Any() &&
                    !entity.GradeIds.Any() &&
                    !entity.JobIds.Any())
                    throw new Exception("厂区、部门、职称、职等、岗位，至少填写任一个才能保存！");
            }


        var result = await base.Add(entity);

        if (entity.Staffs != null && entity.Staffs.Any())
        {
            var insertStaffs = entity.Staffs.Select(x => new InsertGhre_StudyRuleStaffInput
            {
                StaffId = x,
                StudyRuleId = result
            }).ToList();
            await _ghre_StudyRuleStaffServices.Add(insertStaffs);
        }

        string sql = @"UPDATE A
                    SET A.StaffName = B.StaffName
                    FROM Ghre_StudyRuleStaff A LEFT JOIN Ghra_Staff B ON A.StaffId = B.StaffID
                    WHERE A.StaffName IS NULL";
        await Db.Ado.ExecuteCommandAsync(sql);

        await Task.Factory.StartNew(async () => await GenerateStaffStudyRecord(Db, result));
        return result;
    }

    public override async Task<bool> Update(long Id, EditGhre_StudyRuleInput entity)
    {

        if (!entity.ZoneIds.IsNull())
            entity.ZoneId = JsonHelper.ObjToJson(entity.ZoneIds);
        if (!entity.DeptIds.IsNull())
            entity.DeptId = JsonHelper.ObjToJson(entity.DeptIds);
        if (!entity.TitleIds.IsNull())
            entity.TitleId = JsonHelper.ObjToJson(entity.TitleIds);
        if (!entity.GradeIds.IsNull())
            entity.GradeId = JsonHelper.ObjToJson(entity.GradeIds);
        if (!entity.JobIds.IsNull())
            entity.JobId = JsonHelper.ObjToJson(entity.JobIds);

        var companyCode = await QueryCompanyCode();
        if (companyCode != "Viavi")
            if (entity.TrainType == "NewStaff")
            {
                if (!entity.ZoneIds.Any() &&
                    !entity.DeptIds.Any() &&
                    !entity.TitleIds.Any() &&
                    !entity.GradeIds.Any() &&
                    !entity.JobIds.Any())
                    throw new Exception("厂区、部门、职称、职等、岗位，至少填写任一个才能保存！");
            }

        var result = await base.Update(Id, entity);
        await _ghre_StudyRuleStaffServices.Delete(x => x.StudyRuleId == Id);


        if (!entity.IsNull() && entity.Staffs.Any())
        {
            var insertStaffs = entity.Staffs.Select(x => new InsertGhre_StudyRuleStaffInput
            {
                StaffId = x,
                StudyRuleId = Id
            }).ToList();
            await _ghre_StudyRuleStaffServices.Add(insertStaffs);
        }

        string sql = @"UPDATE A
                    SET A.StaffName = B.StaffName
                    FROM Ghre_StudyRuleStaff A LEFT JOIN Ghra_Staff B ON A.StaffId = B.StaffID
                    WHERE A.StaffName IS NULL";
        await Db.Ado.ExecuteCommandAsync(sql);

        await Task.Factory.StartNew(async () => await GenerateStaffStudyRecord(Db, Id));
        return result;
    }

    public override async Task<ServiceFormResult<Ghre_StudyRuleDto>> QueryForm(QueryForm body)
    {
        var result = await base.QueryForm(body);

        if (result.result.DT_TableDataT1.Any())
        {

            var staffs = await _ghre_StudyRuleStaffServices.Query(x => x.StudyRuleId != null && x.StudyRuleId == result.result.DT_TableDataT1[0].Id);

            var DT_TableDataT1 = result.result.DT_TableDataT1;
            DT_TableDataT1.ForEach(rule =>
            {
                rule.Staffs = staffs.Where(x => x.StaffId != null).Select(x => x.StaffId.Value).ToList();
                if (!rule.ZoneId.IsNull())
                    rule.ZoneIds = JsonHelper.JsonToObj<List<int?>>(rule.ZoneId);
                if (!rule.DeptId.IsNull())
                    rule.DeptIds = JsonHelper.JsonToObj<List<int?>>(rule.DeptId);
                if (!rule.TitleId.IsNull())
                    rule.TitleIds = JsonHelper.JsonToObj<List<int?>>(rule.TitleId);
                if (!rule.GradeId.IsNull())
                    rule.GradeIds = JsonHelper.JsonToObj<List<int?>>(rule.GradeId);
                if (!rule.JobId.IsNull())
                    rule.JobIds = JsonHelper.JsonToObj<List<int?>>(rule.JobId);
            });

            result.result.DT_TableDataT1 = DT_TableDataT1;
        }
        return result;
    }

    public async Task<bool> GenerateStaffStudyRecord(ISqlSugarClient Db, long ruleId)
    {
        try
        {
            //await Db.Ado.BeginTranAsync();

            var rule = await Db.Queryable<Ghre_StudyRule>().FirstAsync(x => x.Id == ruleId);

            var ZoneIds = new List<int?>();
            var DeptIds = new List<int?>();
            var TitleIds = new List<int?>();
            var GradeIds = new List<int?>();
            var JobIds = new List<int?>();
            if (!rule.ZoneId.IsNull())
                ZoneIds = JsonHelper.JsonToObj<List<int?>>(rule.ZoneId);
            if (!rule.DeptId.IsNull())
                DeptIds = JsonHelper.JsonToObj<List<int?>>(rule.DeptId);
            if (!rule.TitleId.IsNull())
                TitleIds = JsonHelper.JsonToObj<List<int?>>(rule.TitleId);
            if (!rule.GradeId.IsNull())
                GradeIds = JsonHelper.JsonToObj<List<int?>>(rule.GradeId);
            if (!rule.JobId.IsNull())
                JobIds = JsonHelper.JsonToObj<List<int?>>(rule.JobId);

            await Db.Deleteable<Ghre_StudyRecord>().Where(x => x.StudyRuleId == ruleId && x.BeginTime == null).ExecuteCommandAsync();
            await Db.Deleteable<Ghre_ExamStaff>().Where(x => x.StudyRuleId == ruleId).ExecuteCommandAsync();


            #region 处理部门是否含下阶
            var deptIds = new List<int?>();
            if (rule.IsDeptLower == true && DeptIds.Any())
            {
                var depts = new List<Ghro_Dept>();
                depts = await GetDeptList(depts);

                foreach (var dept in DeptIds)
                {
                    var items = await GetDeptList(depts, dept);
                    deptIds.AddRange(items.Select(x => x.DeptID).ToList());
                }
                deptIds = deptIds.Distinct().ToList();
                if (deptIds.Any())
                    DeptIds.AddRange(deptIds);
            }
            #endregion

            var ruleStaffs = await Db.Queryable<Ghre_StudyRuleStaff>().Where(x => x.StudyRuleId == ruleId).ToListAsync();

            await Db.Updateable<Ghre_StudyRuleResult>().Where(x => x.StudyRuleId == ruleId && x.IsEnable == 1)
                .SetColumns(it => new Ghre_StudyRuleResult() { IsEnable = 0 })
                .ExecuteCommandAsync();

            var ruleStaffIds = ruleStaffs.Select(x => x.StaffId).ToList();

            #region 抓取新入职员工
            int month = 3;
            var inStaffIds = new List<int>();
            if (rule.TrainType == "NewStaff")
            {
                var config = await Db.Queryable<Ghre_Config>().Where(x => x.ConfigCode == "New_Staff_Month").FirstAsync();
                if (config != null)
                {
                    try
                    {
                        month = Convert.ToInt32(config.ConfigValue);
                    }
                    catch (Exception)
                    {

                    }
                    var dateTime = DateTime.Now.AddMonths(-month);

                    inStaffIds = await Db.Queryable<Ghra_Staff>()
                    .Where(x => x.OutDate == null || (x.OutDate != null && x.Indate != null && x.Indate.Value.Date >= dateTime.Date && x.Indate.Value.Date <= DateTime.Now.Date))
                    .Select(x => x.StaffID).ToListAsync();
                }
            }
            #endregion

            var staffs = await Db.Queryable<Ghra_Staff>()
                .WhereIF(inStaffIds.Any(), x => inStaffIds.Contains(x.StaffID))
                .Where(x => x.OutDate == null || (x.OutDate != null && x.Indate != null && x.Indate.Value.Date <= DateTime.Now.Date && x.Indate.Value.Date >= DateTime.Now.Date))
                .WhereIF(ZoneIds.Any(), x => ZoneIds.Contains(x.ZoneID))
                .WhereIF(DeptIds.Any(), x => DeptIds.Contains(x.DeptID))
                .WhereIF(TitleIds.Any(), x => TitleIds.Contains(x.TitleID))
                .WhereIF(GradeIds.Any(), x => GradeIds.Contains(x.GradeID))
                .WhereIF(JobIds.Any(), x => JobIds.Contains(x.JobID))
                .WhereIF(!ruleStaffIds.IsNull() && ruleStaffIds.Any(), x => ruleStaffIds.Contains(x.StaffID))
                .ToListAsync();

            if (staffs.Any())
            {
                var courseTime = Db.GetDate();
                var snap = await Db.Queryable<Ghre_CourseSnap>().FirstAsync(x => x.CourseId == rule.CourseId);

                if (staffs.Any())
                {
                    var inserts = new List<Ghre_StudyRecord>();
                    var insertExamStaffs = new List<Ghre_ExamStaff>();
                    var insertResults = new List<Ghre_StudyRuleResult>();

                    //var exam = await Db.Queryable<Ghre_Exam>()
                    //        .WhereIF(rule.CourseId != null, x => x.CourseId == rule.CourseId)
                    //        .WhereIF(rule.CourseSceneId != null, x => x.CourseSceneId == rule.CourseSceneId)
                    //        .FirstAsync(x => x.Status == Consts.DicExamStatus.RELEASED);

                    var exam = await Db.Queryable<Ghre_Exam>()
                       .Where(x => x.Status == DIC_EXAM_STATUS.RELEASED
                       && ((x.DateType == DicExamDateType.EXAM_DATE
                       && x.BeginTime.Value.Date <= DateTime.Now.Date && x.EndTime.Value.Date >= DateTime.Now.Date) || x.DateType == Consts.DicExamDateType.AFTER_HOW_LONG))
                       .WhereIF(!rule.CourseId.IsNull(), x => x.CourseId == rule.CourseId)
                       .WhereIF(!rule.CourseSceneId.IsNull(), x => x.CourseSceneId == rule.CourseSceneId)
                       .FirstAsync();

                    for (int i = 0; i < staffs.Count; i++)
                    {
                        var staff = staffs[i];

                        var record = await Db.Queryable<Ghre_StudyRecord>()
                            .Where(x => x.StudyRuleId != null && x.StaffId == staff.StaffID)
                            .WhereIF(!string.IsNullOrWhiteSpace(rule.Year), x => x.Year == rule.Year)
                            .WhereIF(rule.CourseId != null, x => x.CourseId == rule.CourseId)
                            .WhereIF(rule.CourseSceneId != null, x => x.CourseSceneId == rule.CourseSceneId)
                        //.AS("Ghre_StudyRecord_V")
                            .ClearFilter<IBaseDeleteFilter>().FirstAsync();
                        if (record is null)
                        {
                            inserts.Add(new Ghre_StudyRecord()
                            {
                                StaffId = staff.StaffID,
                                ExamId = exam?.Id,
                                CourseSnapId = snap?.Id,
                                CourseId = rule.CourseId,
                                CourseSceneId = rule.CourseSceneId,
                                StudyRuleId = ruleId,
                                JoinTime = courseTime,
                                CourseBeginTime = courseTime.Date,
                                CourseEndTime = courseTime.Date.AddMonths((rule.DeadlineMonth ?? snap?.ValidityPeriod) ?? 1),
                                CourseType = rule.RuleType,
                                CourseStatus = Consts.DIC_STUDY_RECORD_COURSE_STATUS_IN,
                                StudyStatus = Consts.DIC_STUDY_RECORD_STUDY_STATUS.NO_JOIN,
                                Year = rule.Year,
                                PlanId = rule.PlanId,
                                StudyProgress = 0
                            });
                            insertResults.Add(new Ghre_StudyRuleResult()
                            {
                                StaffId = staff.StaffID,
                                StudyRuleId = ruleId,
                                Status = "SUCCESS",
                                RemarkSz = inStaffIds.Where(o => o == staff.StaffID).Any() ? $"生成成功，{month}月内入职员工！" : "生成成功！"
                            });

                            if (exam != null)
                                if (!await Db.Queryable<Ghre_ExamStaff>().AnyAsync(x => x.ExamId == exam.Id && x.StaffId == staff.StaffID))
                                    insertExamStaffs.Add(new Ghre_ExamStaff()
                                    {
                                        ExamId = exam.Id,
                                        StudyRuleId = ruleId,
                                        StaffId = staff.StaffID,
                                        Source = "StudyRule" + rule.RuleType
                                    });
                        }
                        else
                        {
                            if (record.StudyRuleId == ruleId)
                            {
                                insertResults.Add(new Ghre_StudyRuleResult()
                                {
                                    StaffId = staff.StaffID,
                                    StudyRuleId = ruleId,
                                    Status = "SUCCESS",
                                    RemarkSz = "生成成功！"
                                });
                            }
                            else
                                insertResults.Add(new Ghre_StudyRuleResult()
                                {
                                    StaffId = staff.StaffID,
                                    StudyRuleId = ruleId,
                                    Status = "FAIL",
                                    RemarkSz = "生成失败，该课程学习记录已被存在！"
                                });
                        }


                    }

                    if (inserts.Any())
                        await Db.Insertable(inserts).ExecuteReturnSnowflakeIdListAsync();
                    if (insertResults.Any())
                        await Db.Insertable(insertResults).ExecuteReturnSnowflakeIdListAsync();

                    if (insertExamStaffs.Any())
                        await Db.Insertable(insertExamStaffs).ExecuteReturnSnowflakeIdListAsync();

                    rule.Result = "数据生成成功";

                }
                else
                    rule.Result = "未匹配到相关关人员数据！";

                await Db.Updateable<Ghre_StudyRule>().Where(x => x.Id == ruleId)
                    .SetColumns(it => new Ghre_StudyRule() { Result = rule.Result })//类只能在表达示里面不能提取
                    .ExecuteCommandAsync();
            }

            #region 处理异动后人员转选修
            var staffIds = staffs.Select(x => x.StaffID).ToList();

            var recordIds = await Db.Queryable<Ghre_StudyRecord>()
                .Where(x => x.StudyRuleId == ruleId && !staffIds.Contains(x.StaffId.Value) &&
                x.StudyStatus != DIC_STUDY_RECORD_STUDY_STATUS.HAS_FINISH && x.Reverse9 != "异动转入选修")
                .Select(x => x.Id).ToListAsync();
            if (recordIds.Any())
                await Db.Updateable<Ghre_StudyRecord>()
                    .Where(x => recordIds.Contains(x.Id))
                    .SetColumns(it => new Ghre_StudyRecord() { CourseType = "Elective", Reverse9 = "异动转入选修" })
                    .ExecuteCommandAsync();
            #endregion

            //await Db.Ado.CommitTranAsync();

            string sql = @"UPDATE A
                        SET A.StaffName = B.StaffName, a.StaffNo = B.StaffNo
                        FROM Ghre_StudyRuleResult A LEFT JOIN Ghra_Staff B ON A.StaffId = B.StaffID
                        WHERE A.StaffName IS NULL";
            await Db.Ado.ExecuteCommandAsync(sql);
        }
        catch (Exception E)
        {
            //await Db.Ado.RollbackTranAsync();

            await Db.Updateable<Ghre_StudyRule>().Where(x => x.Id == ruleId)
                  .SetColumns(it => new Ghre_StudyRule() { Result = E.Message })
                  .ExecuteCommandAsync();
        }
        return true;
    }

    public async Task StaffIn()
    {
        var rules = await Db.Queryable<Ghre_StudyRule>().Where(x => x.TrainType != DIC_TRAINING_STUDY_RULE_TRAIN_TYPE.Year && x.TrainType != DIC_TRAINING_STUDY_RULE_TRAIN_TYPE.Orientation).ToListAsync();

        for (int j = 0; j < rules.Count; j++)
        {
            await GenerateStaffStudyRecord(Db, rules[j].Id);
        }
    }

    public async Task StaffIn2()
    {
        var dt = Db.GetDate();
        var depts = new List<Ghro_Dept>();
        depts = await GetDeptList(depts);
        var rules = await Db.Queryable<Ghre_StudyRule>().Where(x => x.TrainType != DIC_TRAINING_STUDY_RULE_TRAIN_TYPE.PreWork && x.TrainType != DIC_TRAINING_STUDY_RULE_TRAIN_TYPE.Orientation).ToListAsync();

        for (int j = 0; j < rules.Count; j++)
        {
            var rule = rules[j];
            var ruleId = rule.Id;
            var ZoneIds = new List<int?>();
            var DeptIds = new List<int?>();
            var TitleIds = new List<int?>();
            var GradeIds = new List<int?>();
            var JobIds = new List<int?>();
            if (!rule.ZoneId.IsNull())
                ZoneIds = JsonHelper.JsonToObj<List<int?>>(rule.ZoneId);
            if (!rule.DeptId.IsNull())
                DeptIds = JsonHelper.JsonToObj<List<int?>>(rule.DeptId);
            if (!rule.TitleId.IsNull())
                TitleIds = JsonHelper.JsonToObj<List<int?>>(rule.TitleId);
            if (!rule.GradeId.IsNull())
                GradeIds = JsonHelper.JsonToObj<List<int?>>(rule.GradeId);
            if (!rule.JobId.IsNull())
                JobIds = JsonHelper.JsonToObj<List<int?>>(rule.JobId);

            #region 处理部门是否含下阶
            var deptIds = new List<int?>();
            if (rule.IsDeptLower == true && DeptIds.Any())
            {
                foreach (var dept in DeptIds)
                {
                    var items = await GetDeptList(depts, dept);
                    deptIds.AddRange(items.Select(x => x.DeptID).ToList());
                }
                deptIds = deptIds.Distinct().ToList();
                if (deptIds.Any())
                    DeptIds.AddRange(deptIds);
            }
            #endregion

            var staffs = await Db.Queryable<Ghra_Staff>()
                .Where(x => x.Indate != null && x.Indate.Value.Date == dt.Date)
                .WhereIF(ZoneIds.Any(), x => ZoneIds.Contains(x.ZoneID))
                .WhereIF(DeptIds.Any(), x => DeptIds.Contains(x.DeptID))
                .WhereIF(TitleIds.Any(), x => TitleIds.Contains(x.TitleID))
                .WhereIF(GradeIds.Any(), x => GradeIds.Contains(x.GradeID))
                .WhereIF(JobIds.Any(), x => JobIds.Contains(x.JobID))
                .Select(x => new
                {
                    x.StaffID,
                    x.StaffEname,
                    x.Indate,
                    x.OutDate
                })
                .ToListAsync();


            if (!staffs.IsNull())
            {
                if (staffs.Any())
                {
                    var snap = await Db.Queryable<Ghre_CourseSnap>().FirstAsync(x => x.CourseId == rule.CourseId);

                    var inserts = new List<Ghre_StudyRecord>();
                    var insertExamStaffs = new List<Ghre_ExamStaff>();
                    var insertResults = new List<Ghre_StudyRuleResult>();

                    //var exam = await Db.Queryable<Ghre_Exam>()
                    //        .WhereIF(rule.CourseId != null, x => x.CourseId == rule.CourseId)
                    //        .WhereIF(rule.CourseSceneId != null, x => x.CourseSceneId == rule.CourseSceneId)
                    //        .FirstAsync(x => x.Status == Consts.DicExamStatus.RELEASED);

                    var exam = await Db.Queryable<Ghre_Exam>()
                       .Where(x => x.Status == Consts.DIC_EXAM_STATUS.RELEASED
                       && ((x.DateType == Consts.DicExamDateType.EXAM_DATE
                       && x.BeginTime.Value.Date <= DateTime.Now.Date && x.EndTime.Value.Date >= DateTime.Now.Date) || x.DateType == Consts.DicExamDateType.AFTER_HOW_LONG))
                       .WhereIF(!rule.CourseId.IsNull(), x => x.CourseId == rule.CourseId)
                       .WhereIF(!rule.CourseSceneId.IsNull(), x => x.CourseSceneId == rule.CourseSceneId)
                       .FirstAsync();

                    for (int i = 0; i < staffs.Count; i++)
                    {
                        var staff = staffs[i];

                        var record = await Db.Queryable<Ghre_StudyRecord>()
                            .Where(x => x.StudyRuleId != ruleId && x.StaffId == staff.StaffID)
                            .WhereIF(!string.IsNullOrWhiteSpace(rule.Year), x => x.Year == rule.Year)
                            .WhereIF(rule.CourseId != null, x => x.CourseId == rule.CourseId)
                            .WhereIF(rule.CourseSceneId != null, x => x.CourseSceneId == rule.CourseSceneId)
                            //.AS("Ghre_StudyRecord_V")
                            .FirstAsync();
                        if (record is null)
                        {
                            inserts.Add(new Ghre_StudyRecord()
                            {
                                StaffId = staff.StaffID,
                                ExamId = exam?.Id,
                                CourseSnapId = snap?.Id,
                                CourseId = rule.CourseId,
                                CourseSceneId = rule.CourseSceneId,
                                StudyRuleId = ruleId,
                                JoinTime = dt,
                                CourseBeginTime = dt.Date,
                                CourseEndTime = dt.Date.AddMonths((rule.DeadlineMonth ?? snap?.ValidityPeriod) ?? 1),
                                CourseType = rule.RuleType,
                                CourseStatus = Consts.DIC_STUDY_RECORD_COURSE_STATUS_IN,
                                StudyStatus = Consts.DIC_STUDY_RECORD_STUDY_STATUS.NO_JOIN,
                                Year = rule.Year
                            });
                            insertResults.Add(new Ghre_StudyRuleResult()
                            {
                                StaffId = staff.StaffID,
                                StudyRuleId = ruleId,
                                Status = "SUCCESS",
                                RemarkSz = "生成成功"
                            });

                            if (exam != null)
                                if (!await Db.Queryable<Ghre_ExamStaff>().AnyAsync(x => x.ExamId == exam.Id && x.StaffId == staff.StaffID))
                                    insertExamStaffs.Add(new Ghre_ExamStaff()
                                    {
                                        ExamId = exam.Id,
                                        StudyRuleId = ruleId,
                                        StaffId = staff.StaffID,
                                        Source = "StudyRule" + rule.RuleType
                                    });
                        }
                        else insertResults.Add(new Ghre_StudyRuleResult()
                        {
                            StaffId = staff.StaffID,
                            StudyRuleId = ruleId,
                            Status = "FAIL",
                            RemarkSz = "生成失败，该课程学习记录已被其他规则生成！"
                        });
                    }

                    if (inserts.Any())
                        await Db.Insertable(inserts).ExecuteReturnSnowflakeIdListAsync();
                    if (insertResults.Any())
                        await Db.Insertable(insertResults).ExecuteReturnSnowflakeIdListAsync();

                    if (insertExamStaffs.Any())
                        await Db.Insertable(insertExamStaffs).ExecuteReturnSnowflakeIdListAsync();
                }
            }
        }
    }

    #region 删除
    // <summary>
    /// 删除指定ID的数据
    /// </summary>
    /// <param name="id">主键ID</param>
    /// <returns></returns>
    public override async Task<bool> DeleteById1(object id)
    {
        var companyCode = await QueryCompanyCode();
        if (companyCode != "Viavi")
        {
            if (await Db.Queryable<Ghre_StudyRecord>().AnyAsync(x => x.StudyRuleId == id.ObjToLong() && x.StudyStatus != Consts.DIC_STUDY_RECORD_STUDY_STATUS.NO_JOIN))
                throw new Exception($"有学员已经学习，暂不可作废！");
        }

        await Db.Updateable<Ghre_StudyRecord>()
          .SetColumns(it => new Ghre_StudyRecord()
          {
              IsEnable = 0,
              UpdateTime = DateTime.Now,
              UpdateBy = App.User.ID
          })
          .Where(it => it.StudyRuleId == id.ObjToLong())
          .ExecuteCommandAsync();

        return await base.DeleteById1(id);
    }

    /// <summary>
    /// 删除指定ID集合的数据(批量删除)
    /// </summary>
    /// <param name="ids">主键ID集合</param>
    /// <returns></returns>
    public override async Task<bool> DeleteByIds1(long[] ids)
    {

        foreach (var id in ids)
        {
            if (await Db.Queryable<Ghre_StudyRecord>().AnyAsync(x => x.StudyRuleId == id.ObjToLong() && x.StudyStatus != Consts.DIC_STUDY_RECORD_STUDY_STATUS.NO_JOIN))
                throw new Exception($"有学员已经学习，暂不可作废！");
        }

        return await base.DeleteByIds1(ids);
    }
    #endregion
}