
using Tiobon.Core.IServices;
using Tiobon.Core.Model.Models;
using Tiobon.Core.Services.BASE;
using Tiobon.Core.IRepository.Base;
using Tiobon.Core.Common.Caches;
using Newtonsoft.Json.Linq;
using Tiobon.Core.Common;
using Tiobon.Core.Model;
using Newtonsoft.Json;
using Tiobon.Core.Common.Helper;
using SqlSugar;
using static Tiobon.Core.Model.Consts;

namespace Tiobon.Core.Services
{
    /// <summary>
    /// 培训记录 (服务)
    /// </summary>
    public class Ghre_StudyRecordServices : BaseServices<Ghre_StudyRecord, Ghre_StudyRecordDto, InsertGhre_StudyRecordInput, EditGhre_StudyRecordInput>, IGhre_StudyRecordServices
    {
        private readonly IBaseRepository<Ghre_StudyRecord> _dal;
        public Ghre_StudyRecordServices(ICaching caching, IBaseRepository<Ghre_StudyRecord> dal)
        {
            this._dal = dal;
            base.BaseDal = dal;
            base._caching = caching;
        }
        public override async Task<ServicePageResult<Ghre_StudyRecordDto>> 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_StudyRecord_V";
            var sql = @$" SELECT *
                    FROM Ghre_StudyRecord_V  A";

            string conditions = " WHERE 1=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 == "Date")
                    {
                        var jsonParam = JsonConvert.DeserializeObject<JsonParam1>(value);
                        conditions += $" AND (Date BETWEEN '{jsonParam.columnValue[0]}' AND '{jsonParam.columnValue[1]}')";

                        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_StudyRecordDto>(sql);

            entitys.ForEach(entity =>
            {
                if (!string.IsNullOrWhiteSpace(entity.Indate))
                    entity.Indate = DateTimeHelper.ConvertToDayString(entity.Indate);
                entity.ExamDate = DateTimeHelper.ConvertToDayString(entity.ExamDate);
            });

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

        }


        #region 获取ESS查询条件
        public async Task<ServiceResult<CoursePublicSearch>> QueryESSSearchFields(QueryBody body)
        {
            var entity = new CoursePublicSearch();
            string sql = @"SELECT Langkey field,
                       CASE {2}
                          WHEN 1 THEN isnull (Value01, LangValue)
                          WHEN 2 THEN isnull (Value02, LangValue)
                          WHEN 3 THEN isnull (Value03, LangValue)
                          WHEN 4 THEN isnull (Value04, LangValue)
                          WHEN 5 THEN isnull (Value05, LangValue)
                          WHEN 6 THEN isnull (Value06, LangValue)
                          WHEN 7 THEN isnull (Value07, LangValue)
                          WHEN 8 THEN isnull (Value08, LangValue)
                          WHEN 9 THEN isnull (Value09, LangValue)
                          WHEN 10 THEN isnull (Value10, LangValue)
                       END label
                FROM Ghrs_LangKey
                WHERE     IsEnable = 1
                      AND (LangKey LIKE 'GHR_Page%' OR LangKey LIKE 'GHR_Common%')";
            sql = string.Format(sql, body.menuName, App.User.ID, body.langId);
            entity.DT_PageMutiMsg = await Db.Ado.SqlQueryAsync<DT_PageMutiMsg>(sql);
            entity.SearchFields.Add(new CoursePublicSearchField()
            {
                label = "课程编号/名称",
                field = "CourseNoOrName",
                elementType = "Input",
                editable = true,
                required = false,
                multipleSelect = false,
            });
            entity.SearchFields.Add(new CoursePublicSearchField()
            {
                label = "课程分类",
                field = "CourseClassId",
                elementType = "ApiSelect",
                dataSource = "CommonList_TrainingCourseClass",
                editable = true,
                required = false,
                multipleSelect = false,
            });
            entity.SearchFields.Add(new CoursePublicSearchField()
            {
                label = "课程场景",
                field = "CourseSceneId",
                elementType = "ApiSelect",
                dataSource = "CommonList_TrainingCourseScene",
                editable = true,
                required = false,
                multipleSelect = false,
            });
            entity.SearchFields.Add(new CoursePublicSearchField()
            {
                label = "课程状态",
                field = "CourseStatus",
                elementType = "ApiSelect",
                dataSource = "TBParaDetail_Train_CourseIsOpen",
                editable = true,
                required = false,
                multipleSelect = false,
            });
            entity.SearchFields.Add(new CoursePublicSearchField()
            {
                label = "学习状态",
                field = "StudyStatus",
                elementType = "ApiSelect",
                dataSource = "TBParaDetail_Train_TrainingStudyStatus",
                editable = true,
                required = false,
                multipleSelect = false,
            });
            return ServiceResult<CoursePublicSearch>.OprateSuccess("", entity);
        }
        #endregion

        #region 获取我的学习
        /// <summary>
        /// 
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="condition"></param>
        /// <param name="IsEnable"></param>
        /// <returns></returns>
        public async Task<ServicePageResult<Ghre_StudyRecordESS>> QueryESS(QueryBody filter, string condition, bool? IsEnable = true)
        {
            if (string.IsNullOrWhiteSpace(filter.orderBy))
                filter.orderBy = "JoinTime DESC";

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

            var countSql = @$" SELECT COUNT(1) FROM  Ghre_StudyRecord_V";
            var sql = @$" SELECT A.Id,
                               A.StaffId,
                               A.CourseSnapId,
                               A.CourseId,
                               A.CoverUrl,
                               A.UseDefaultCoverImage,
                               A.DefaultCoverImageName,
                               A.CourseName,
                               A.StandardHour,
                               A.CourseCreditPoints CreditPoints,
                               A.CourseBeginTime CourseBeginDate,
                               A.CourseEndTime CourseEndDate,
                               A.ExamDate,
                               A.ExamBeginDate,
                               A.ExamEndDate,
                               A.JoinTime,
                               A.CourseClassId,
                               A.CourseSceneId,
                               A.CourseType,
                               A.ExamDateType,
                               A.AfterHowLong,
                               A.StudyProgress,
                               A.ExamId
                        FROM Ghre_StudyRecord_V A";

            string conditions = $" WHERE UserId={App.User.ID} ";

            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 == "CourseNoOrName")
                    {
                        var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                        conditions += $" AND CourseName LIKE '%{jsonParam.columnValue}%'";

                        continue;
                    }
                    if (name == "CourseClassId")
                    {
                        var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                        conditions += $" AND CourseClassId LIKE '%{jsonParam.columnValue}%' ";

                        continue;
                    }
                    if (name == "CourseType")
                    {
                        var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);

                        var value1 = jsonParam.columnValue;
                        conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'";

                        continue;
                    }
                    if (!string.IsNullOrWhiteSpace(value))
                    {
                        var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);

                        switch (jsonParam.operationKey)
                        {
                            case "Include":
                                conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'";
                                break;
                            case "NotInclude":
                                conditions += $" AND {name} NOT LIKE '%{jsonParam.columnValue}%'";
                                break;
                            case "IsNull":
                                conditions += $" AND {name} IS NULL";
                                break;
                            case "NotNull":
                                conditions += $" AND {name} IS NOT NULL";
                                break;
                            case "Equal":
                                conditions += $" AND {name} ='{jsonParam.columnValue}'";
                                break;
                            case "NotEqual":
                                conditions += $" AND {name} !='{jsonParam.columnValue}'";
                                break;
                            case "GreaterOrEqual"://大于等于
                                conditions += $" AND {name} >='{jsonParam.columnValue}'";
                                break;
                            case "Greater"://大于
                                conditions += $" AND {name} >'{jsonParam.columnValue}'";
                                break;
                            case "LessOrEqual"://小于等于
                                conditions += $" AND {name} <='{jsonParam.columnValue}'";
                                break;
                            case "Less"://小于
                                conditions += $" AND {name} <'{jsonParam.columnValue}'";
                                break;
                            default:
                                break;
                        }
                    }
                }

            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_StudyRecordESS>(sql);
            var dt = DateTime.Now.Date;
            entitys.ForEach(x =>
            {
                if (x.CourseBeginDate != null && x.CourseEndDate != null)
                    x.CourseDateString = DateTimeHelper.ConvertToDayString(x.CourseBeginDate) + "~" + DateTimeHelper.ConvertToDayString(x.CourseEndDate);

                if (!x.ExamId.IsNull())
                {
                    if (x.ExamBeginDate != null && x.ExamEndDate != null)
                        x.ExamDateString = DateTimeHelper.ConvertToDayString(x.ExamBeginDate) + "~" + DateTimeHelper.ConvertToDayString(x.ExamEndDate);
                    else x.ExamDateString = $"学完{x.AfterHowLong}天";
                }

                //if (x.CourseBeginDate != null && x.CourseEndDate != null)
                //    if (x.StudyProgress >= 100 || !(x.CourseBeginDate.Value.Date <= DateTime.Now.Date && x.CourseEndDate.Value.Date >= DateTime.Now.Date))
                //        x.DisableStudyBtn = true;

                if (x.StudyProgress < 100 || x.ExamId.IsNull())
                    x.DisableExamBtn = true;
                if (x.FeedbackOrderId.IsNull())
                    x.ShowFeedbackBtn = false;
            });

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

        }

        #endregion 

        #region 获取课程
        /// <summary>
        /// 获取课程
        /// </summary>
        /// <param name="courseId"></param> 
        /// <returns></returns>
        public async Task<ServiceResult<Ghre_StudyRecordCourse>> QueryCourse(QueryBody body, long id)
        {
            var course = new Ghre_StudyRecordCourse();

            string sql = @$"SELECT A.Id,
                               A.CourseId,
                               A.CourseSceneId,
                               ISNULL (B.CourseName, G.SceneName) CourseName,
                               B.UseDefaultCoverImage,
                               B.DefaultCoverImageName,
                               B.CoverUrl,
                               B.SchoolTeacherId,
                               B.SchoolId,
                               B.InOrOut,
                               E.TeacherName,
                               --  E.TeacherEName,


                               CASE B.InOrOut
                                  WHEN 'In' THEN C.StaffEname
                                  WHEN 'Out' THEN NULL
                                  ELSE NULL
                               END AS TeacherEName,
                               E.PhotoUrl TeacherPhotoUrl,
                               CASE B.InOrOut
                                  WHEN 'In'
                                  THEN
                                     dbo.FO_DeptInfo (E.DeptID,
                                                      getdate (),
                                                      1,
                                                      'DeptFullPateName')
                                  WHEN 'Out'
                                  THEN
                                     F.SchoolName
                                  ELSE
                                     NULL
                               END AS DeptOrSchoolName,
                               E.SkillPoints TeacherRemarkSz,
                               B.StandardHour,
                               B.CreditPoints,
                               B.Outline CourseRemarkSz,
                               A.StudyProgress,
                               A.CourseBeginTime,
                               A.CourseEndTime
                        FROM Ghre_StudyRecord A
                             LEFT JOIN Ghre_Course B ON A.CourseId = B.Id
                             LEFT JOIN Ghra_Staff c ON B.TeacherId = c.StaffID
                             LEFT JOIN Ghre_Teacher E ON B.SchoolTeacherId = E.Id
                             LEFT JOIN Ghre_School F ON B.SchoolId = F.Id
                             LEFT JOIN Ghre_CourseScene G ON A.CourseSceneId = G.Id
                        WHERE A.Id = '{id}'";
            course = await Db.Ado.SqlQuerySingleAsync<Ghre_StudyRecordCourse>(sql);
            if (course.IsNull())
                return ServiceResult<Ghre_StudyRecordCourse>.OprateFailed("无效的学习记录ID！");

            if (course.CourseSceneId.IsNull())
            {
                sql = @$"SELECT A.Id, A.Source, A.Link
                        FROM Ghre_CourseWare A
                        WHERE A.CourseIds LIKE '%{course.CourseId}%' AND A.IsEnable = 1";

                course.CourseWareList = await Db.Ado.SqlQueryAsync<Ghre_StudyRecordCourseWare>(sql);

                course.CourseWareList.ForEach(x =>
                {
                    x.CourseId = course.CourseId;
                    x.CourseName = course.CourseName;
                });
                course.CourseTeacherList =
                [
                    new Ghre_StudyRecordCourseTeacher() {
                        TeacherName = course.TeacherName,
                        TeacherEName = course.TeacherEName,
                        TeacherPhotoUrl = course.TeacherPhotoUrl,
                        DeptOrSchoolName = course.DeptOrSchoolName,
                        TeacherRemarkSz = course.TeacherRemarkSz
                    }
                ];
            }
            else
            {
                course.CourseWareList = new List<Ghre_StudyRecordCourseWare>();
                course.CourseTeacherList = new List<Ghre_StudyRecordCourseTeacher>();
                var courses = await Db.Queryable<Ghre_Course>().Where(x => x.CourseSceneId == course.CourseSceneId && x.Status == Consts.DIC_COURSE_STATUS.RELEASED).ToListAsync();

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

                    sql = @$"SELECT A.Id, A.Source, A.Link
                        FROM Ghre_CourseWare A
                        WHERE A.CourseIds LIKE '%{course1.Id}%' AND A.IsEnable = 1";

                    var courseWareList = await Db.Ado.SqlQueryAsync<Ghre_StudyRecordCourseWare>(sql);
                    courseWareList.ForEach(x =>
                    {
                        x.CourseId = course.CourseId;
                        x.CourseName = course.CourseName;
                    });
                    course.CourseWareList.AddRange(courseWareList);



                    sql = $@"SELECT a.ID,
                               C.TeacherName,
                               CASE A.InOrOut
                                  WHEN 'In' THEN B.StaffEname
                                  WHEN 'Out' THEN NULL
                                  ELSE NULL
                               END AS TeacherEName,
                               C.PhotoUrl TeacherPhotoUrl,
                               CASE A.InOrOut
                                  WHEN 'In'
                                  THEN
                                     dbo.FO_DeptInfo (b.DeptID,
                                                      getdate (),
                                                      1,
                                                      'DeptFullPateName')
                                  WHEN 'Out'
                                  THEN
                                     D.SchoolName
                                  ELSE
                                     NULL
                               END AS DeptOrSchoolName,
                               c.SkillPoints TeacherRemarkSz,
                               a.CourseName
                        FROM Ghre_Course A
                             LEFT JOIN Ghra_Staff B ON A.TeacherId = B.StaffID
                             LEFT JOIN Ghre_Teacher C ON A.SchoolTeacherId = C.Id
                             LEFT JOIN Ghre_School D ON C.SchoolId = D.Id
                        WHERE a.id = '{course1.Id}'";

                    course.CourseTeacherList.Add(await Db.Ado.SqlQuerySingleAsync<Ghre_StudyRecordCourseTeacher>(sql));

                }
            }

            for (int j = 0; j < course.CourseWareList.Count; j++)
            {
                course.CourseWareList[j].Attachments = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => x.CourseWareId == course.CourseWareList[j].Id).ToListAsync();
            }

            if (course.CourseBeginTime != null && course.CourseEndTime != null)
                course.CourseDateString = DateTimeHelper.ConvertToDayString(course.CourseBeginTime) + "~" + DateTimeHelper.ConvertToDayString(course.CourseEndTime);

            return ServiceResult<Ghre_StudyRecordCourse>.OprateSuccess("查询成功！", course);
        }

        #endregion

        #region 加入学习
        public async Task<ServiceResult> Join(long courseId)
        {
            var staffId = GetStaffId();
            if (!await base.AnyAsync(x => x.CourseId == courseId && x.StaffId == staffId))
            {
                var course = await Db.Queryable<Ghre_Course>().Where(x => x.Id == courseId && x.Status == DIC_COURSE_STATUS.RELEASED).FirstAsync();
                if (course.IsNull())
                    return ServiceResult.OprateFailed("无效的课程！");

                DateTime courseTime = Db.GetDate();
                var snap = await Db.Queryable<Ghre_CourseSnap>().FirstAsync(x => x.CourseId == courseId);

                var exam = await Db.Queryable<Ghre_Exam>()
                    .Where(x => x.Status == DIC_EXAM_STATUS.RELEASED &&
                    x.CourseId == courseId
                    && ((x.DateType == DicExamDateType.EXAM_DATE
                    && x.BeginTime.Value.Date <= DateTime.Now.Date && x.EndTime.Value.Date >= DateTime.Now.Date) || x.DateType == DicExamDateType.AFTER_HOW_LONG))
                    .FirstAsync();
                await base.Add(new InsertGhre_StudyRecordInput
                {
                    StaffId = staffId,
                    CourseSnapId = snap?.Id,
                    CourseId = courseId,
                    JoinTime = courseTime,
                    CourseBeginTime = courseTime.Date,
                    CourseEndTime = courseTime.Date.AddMonths(snap?.ValidityPeriod ?? 1),
                    CourseType = "ManualElective",
                    CourseStatus = DIC_STUDY_RECORD_COURSE_STATUS_IN,
                    StudyStatus = DicStudyRecordStudyStatus.NO_JOIN,
                    ExamId = exam?.Id
                });
            }
            return ServiceResult.OprateSuccess("加入成功！");
        }
        #endregion

        #region 记录学习时长
        public async Task<ServiceResult> RecordDuration(long studyRecordId, decimal? duration)
        {
            var staffId = GetStaffId();
            var sql = $"UPDATE Ghre_StudyRecord SET StudyDuration = ISNULL(StudyDuration, 0)+{duration} WHERE Id='{studyRecordId}' AND  StaffId='{staffId}'";
            await Db.Ado.ExecuteCommandAsync(sql);

            await Task.Factory.StartNew(async () => await GenerateStaffStudyRecord(Db, studyRecordId));


            return ServiceResult.OprateSuccess("记录成功！");
        }

        public async Task<bool> GenerateStaffStudyRecord(ISqlSugarClient Db, long studyRecordId)
        {
            var record = await Db.Queryable<Ghre_StudyRecord>().FirstAsync(x => x.Id == studyRecordId);


            decimal studyProgress = 0;
            var sql = $@"SELECT ISNULL (A.Hours, 0) * 60 + A.Minutes Minutes
                            FROM Ghre_CourseWare A
                            WHERE A.Id IN
                                     (SELECT CourseWareId
                                      FROM Ghre_Course
                                      WHERE    Id = '{record.CourseId}'
                                            OR CourseSceneId = '{record.CourseSceneId}' AND IsEnable = 1)";
            var mins = await Db.Ado.GetDecimalAsync(sql);

            if (mins > 0)
            {
                var duration = record.StudyDuration ?? 0;
                studyProgress = (duration / mins) * 100;
                if (studyProgress > 100)
                    studyProgress = 100;
            }

            var studyStatus = DicStudyRecordStudyStatus.NO_FINISH;
            if (studyProgress == 100)
                studyStatus = DicStudyRecordStudyStatus.HAS_FINISH;

            sql = $"UPDATE Ghre_StudyRecord SET StudyProgress = {studyProgress},StudyStatus='{studyStatus}' WHERE Id='{studyRecordId}'";
            if (studyProgress > 0) await Db.Ado.ExecuteCommandAsync(sql);
            sql = $"UPDATE Ghre_StudyRecord SET BeginTime=GETDATE(),StudyStatus='{studyStatus}' WHERE BeginTime IS NULL AND Id='{studyRecordId}'";
            await Db.Ado.ExecuteCommandAsync(sql);

            if (studyProgress == 100)
            {
                sql = $"UPDATE Ghre_StudyRecord SET EndTime=GETDATE() WHERE EndTime IS NULL AND Id='{studyRecordId}'";
                await Db.Ado.ExecuteCommandAsync(sql);
            }
            return true;
        }
        #endregion
    }
}