using Entity.Sugar;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EasyBL
{
    public class AttendanceMethods
    {

        /// <summary>
        /// 彈性工時計算
        /// </summary>
        /// <param name="attendanceRule"></param>
        /// <param name="SignIn"></param>
        /// <returns>依序:工作起、工作迄、是否遲到</returns>
        public Tuple<string, string, bool> GetFlexTime(AttendanceRule attendanceRule, string SignIn)
        {
            var UseStartTime = @""; //實際使用上班時間。
            var UseEndTime = @""; //實際使用上班時間。
            var AnyBuffer = true;
            var WorkDelay = false;
            if (string.IsNullOrWhiteSpace(attendanceRule.WorkStartBuffer))
            {
                AnyBuffer = false;
            }

            
            //檢查有無buffer
            if (AnyBuffer)
            {
                var SignInTime = Convert.ToDateTime(SignIn);
                var StandardWorkStart = Convert.ToDateTime(attendanceRule.WorkStart);
                var StandardWorkEnd = Convert.ToDateTime(attendanceRule.WorkEnd);
                var BufferedWorkStart = Convert.ToDateTime(attendanceRule.WorkStartBuffer + ":59");
                //-1: t1 早於 t2。 0: t1 與 t2 相同。 1: t1 晚於 t2。
                var CheckStandardThreadhold = DateTime.Compare(SignInTime, StandardWorkStart) > 0;
                if (CheckStandardThreadhold)
                {
                    var CheckBufferThreadhold = DateTime.Compare(SignInTime, BufferedWorkStart);
                    switch (CheckBufferThreadhold)
                    {
                        case 1:
                            WorkDelay = true;
                            var TotalBufferHour = ExecDateDiff(StandardWorkStart, BufferedWorkStart);
                            StandardWorkEnd = StandardWorkEnd.AddHours(TotalBufferHour);
                            if (attendanceRule.DelayBuffer > 0)
                            {
                                BufferedWorkStart = BufferedWorkStart.AddMinutes(-1 * attendanceRule.DelayBuffer);
                                StandardWorkEnd = StandardWorkEnd.AddMinutes(-1 * attendanceRule.DelayBuffer);
                            }
                            UseEndTime = StandardWorkEnd.ToString("HH:mm");
                            UseStartTime = BufferedWorkStart.ToString("HH:mm");

                            break;
                        case 0:
                        case -1:
                            var WorkStartBuffer = ExecDateDiff(StandardWorkStart, SignInTime);
                            WorkDelay = false;
                            UseEndTime = StandardWorkEnd.AddHours(WorkStartBuffer).ToString("HH:mm");
                            UseStartTime = StandardWorkStart.AddHours(WorkStartBuffer).ToString("HH:mm");
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    WorkDelay = false;
                    UseEndTime = attendanceRule.WorkEnd;
                    UseStartTime = attendanceRule.WorkStart;
                }
            }
            //無緩衝
            else
            {
                WorkDelay = DateTime.Compare(Convert.ToDateTime(SignIn), Convert.ToDateTime(attendanceRule.WorkStart)) > 0;
                UseStartTime = attendanceRule.WorkStart;
                UseEndTime = attendanceRule.WorkEnd;
                
            }
            return new Tuple<string, string,bool>(UseStartTime, UseEndTime, WorkDelay);
        }

        /// <summary>
        /// 計算工作時間。
        /// 必須SignOut、SignIn有時間,SignOut晚於SignIn、TimeA(工作時間起)和TimeP(工作時間迄)
        /// </summary>
        /// <param name="sSignTime"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public double GetWorkingHour(string sSignTime, OTB_EIP_Attendance info)
        {
            var WorkingHour = 0.0;
            var CheckAvaliableTime = !string.IsNullOrWhiteSpace(info.SignOut) && !string.IsNullOrWhiteSpace(info.SignIn);
            var HasDiffTime = ExecDateDiff(Convert.ToDateTime(info.SignIn), Convert.ToDateTime(info.SignOut)) > 0;
            var HasWorkTime = !string.IsNullOrWhiteSpace(info.TimeA) && !string.IsNullOrWhiteSpace(info.TimeP);
            if (CheckAvaliableTime && HasDiffTime && HasWorkTime)
            {
                var StandardWorkStart = Convert.ToDateTime(info.TimeA);
                var StandardWorkEnd = Convert.ToDateTime(info.TimeP);
                var SignInTime = Convert.ToDateTime(info.SignIn);
                if (SignInTime.Second > 0) //取最小量
                    SignInTime = SignInTime.AddSeconds(-1 * SignInTime.Second);
                var SignOutTime = Convert.ToDateTime(sSignTime);
                if (SignOutTime.Second > 0) //取最大量
                    SignOutTime = SignOutTime.AddSeconds(-1 * SignOutTime.Second);
                var ActualStartTime = new DateTime();
                var ActualEndTime = new DateTime();
                //實際認列開始工作時間。過早一律認列上班時間
                var WorkStartThreadhold = DateTime.Compare(SignInTime, StandardWorkStart);
                //實際認列結束工作時間。
                var WorkEndThreadhold = DateTime.Compare(SignOutTime, StandardWorkEnd);
                switch (WorkStartThreadhold)
                {
                    //刷進時間 晚於 變動上班時間
                    case 1:
                        ActualStartTime = SignInTime;
                        break;
                    //刷進時間 早於(等於) 變動上班時間
                    case 0:
                    case -1:
                        ActualStartTime = StandardWorkStart;
                        break;
                    default:
                        break;
                }
                switch (WorkEndThreadhold)
                {
                    case 1:
                    case 0:
                        ActualEndTime = StandardWorkEnd;
                        break;
                    case -1:
                        ActualEndTime = SignOutTime;
                        break;
                    default:
                        break;
                }
                //實際工作起 早於 實際工作迄(前面條件會變更)
                var TotalWorkTimeThreadhold = DateTime.Compare(ActualStartTime, ActualEndTime);
                switch (TotalWorkTimeThreadhold)
                {
                    case 1:
                    case 0:
                        WorkingHour = 0;
                        break;
                    case -1:
                        WorkingHour = Math.Round(ExecDateDiff(ActualStartTime, ActualEndTime), 2, MidpointRounding.AwayFromZero);
                        break;
                    default:
                        break;
                }

            }
            return WorkingHour;
        }

        /// <summary>
        /// 計算考勤
        /// </summary>
        /// <param name="AllLineDatas">卡中資料</param>
        /// <param name="AttendanceRules">出勤規則</param>
        /// <param name="CardDate">打卡日期</param>
        /// <returns></returns>
        public List<OTB_EIP_Attendance> CalculateAttendance(string[] AllLineDatas, List<AttendanceRule> AttendanceRules, DateTime CardDate)
        {
            var saCardAttendanceInfo = new List<OTB_EIP_Attendance>();

            //讀取打卡信息
            foreach (string str in AllLineDatas)
            {
                //打卡日期,卡號      , 刷卡時間,姓名     ,組織
                //20190701,0410164401,14:03:39,陳OO      ,TE
                var strInfo = str.Split(',');
                var sOrgID = strInfo[4].ToString().Trim();
                if (string.IsNullOrEmpty(sOrgID))
                {
                    continue;
                }
                var sCardDate = strInfo[0].ToString().Trim();
                var sCardId = strInfo[1].ToString().Trim();
                var sSignTime = strInfo[2].ToString().Trim();
                var sCardUserName = strInfo[3].ToString().Trim();
                var sTimeA = @"09:00"; //標準上班時間
                var sTimeP = @"17:30"; //標準下班時間
                var sTimeAE = "";  //允許最彈性下班時間
                var UseStartTime = @""; //實際使用上班時間。
                var UseEndTime = @""; //實際使用上班時間。

                var AnyBuffer = true;
                var ApplyRule = AttendanceRules.Where(ar => ar.OrgID == sOrgID).FirstOrDefault();
                if (ApplyRule != null)
                {
                    sTimeA = ApplyRule.WorkStart;
                    sTimeP = ApplyRule.WorkEnd;
                    sTimeAE = ApplyRule.WorkStartBuffer;
                }

                if (string.IsNullOrWhiteSpace(sTimeAE))
                {
                    AnyBuffer = false;
                    sTimeAE = sTimeP;
                }

                if (saCardAttendanceInfo.Any(x => x.CardId == sCardId))
                {
                    //如果存在則更新打卡信息
                    foreach (OTB_EIP_Attendance info in saCardAttendanceInfo)
                    {
                        if (info.CardId == sCardId)
                        {
                            info.SignOut = sSignTime;
                            var TotalWorkingHours = GetWorkingHour(sSignTime, info);
                            var bStatusP = DateTime.Compare(Convert.ToDateTime(info.TimeP), Convert.ToDateTime(sSignTime)) > 0;
                            info.Hours = TotalWorkingHours.ToString();
                            info.StatusP = bStatusP;
                            break;
                        }
                    }
                }
                //不存在則新增
                else
                {
                    var FlexTime = GetFlexTime(ApplyRule, sSignTime);
                    var oAttendanceInfo = new OTB_EIP_Attendance
                    {
                        OrgID = sOrgID,
                        CardDate = CardDate,
                        CardId = sCardId,
                        TimeA = FlexTime.Item1,
                        TimeP = FlexTime.Item2,
                        CardUserName = sCardUserName,
                        Hours = "0",
                        SignIn = sSignTime,
                        SignOut = ""
                    };

                    oAttendanceInfo.StatusA = FlexTime.Item3;
                    oAttendanceInfo.StatusP = false;
                    oAttendanceInfo.Memo = "";
                    oAttendanceInfo.CreateDate = DateTime.Now;
                    saCardAttendanceInfo.Add(oAttendanceInfo);
                }
            }

            return saCardAttendanceInfo;
        }

        /// <summary>
        /// 取得考勤規則
        /// </summary>
        /// <param name="db"></param>
        /// <param name="ConfigSettings">至少要4個</param>
        /// <returns></returns>
        public List<AttendanceRule> GetAttendanceRule(SqlSugarClient db, List<string> ConfigSettings)
        {
            var AttendanceRule = new List<AttendanceRule>();
            try
            {
                do
                {
                    //WebConfig依序:上班開始時間、上班結束時間、最晚上班時間(工作緩衝時間)、遲到緩衝時間(分)
                    //var ConfigSettings = new List<string>() { Common.ConfigGetValue("", "WorkTimePMKey"), Common.ConfigGetValue("", "WorkTimeAMKey")
                    //    ,Common.ConfigGetValue("", "LatestShiftTimeKey"), Common.ConfigGetValue("", "DelayBufferTimeKey") };
                    var AllOrgIDs = db.Queryable<OTB_SYS_Organization>().Select(it => it.OrgID).ToList().Distinct();

                    if(!ConfigSettings.Any())
                    {
                        ConfigSettings = new List<string> { "WorkTimePM", "WorkTimeAM", "LatestShiftTime", "DelayBufferTime" };
                    }

                    var spWorkTimePMKey = new SugarParameter("@WorkTimePM", ConfigSettings[0]);
                    var spDWorkTimeAMKey = new SugarParameter("@WorkTimeAM", ConfigSettings[1]);
                    var spLatestShiftTimeKey = new SugarParameter("@LatestShiftTime", ConfigSettings[2]);
                    var spDelayBufferKey = new SugarParameter("@DelayBuffer", ConfigSettings[3]);
                    var AllOfSystemSettings = db.Ado.SqlQuery<OTB_SYS_SystemSetting>(@"select *from OTB_SYS_SystemSetting where Effective ='Y' 
                    and SettingItem in (@WorkTimePM, @WorkTimeAM, @LatestShiftTime, @DelayBuffer )", spWorkTimePMKey, spDWorkTimeAMKey, spLatestShiftTimeKey, spDelayBufferKey).ToArray();
                    //
                    foreach (var OrgID in AllOrgIDs)
                    {
                        var attendanceRule = new AttendanceRule() { OrgID = OrgID };
                        foreach (var Key in ConfigSettings)
                        {
                            var MatchedRule = AllOfSystemSettings.Where(s => s.OrgID == OrgID && s.SettingItem == Key).FirstOrDefault();
                            if (MatchedRule != null && !string.IsNullOrWhiteSpace(MatchedRule.SettingValue))
                            {
                                var SplittedTime = MatchedRule.SettingValue.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries);
                                switch (Key)
                                {
                                    case "WorkTimePM":
                                        attendanceRule.WorkStart = SplittedTime[0].PadLeft(5, '0');//開始時間
                                        attendanceRule.WorkTimePMDeadLine = MatchedRule.SettingValue;
                                        break;
                                    case "WorkTimeAM":
                                        attendanceRule.WorkEnd = SplittedTime[1].PadLeft(5, '0');//結束時間
                                        attendanceRule.WorkTimeAMDeadLine = MatchedRule.SettingValue;
                                        break;
                                    case "LatestShiftTime":
                                        attendanceRule.WorkStartBuffer = SplittedTime[0].PadLeft(5, '0');
                                        break;
                                    case "DelayBufferTime":
                                        var DelayBuffer = 0;
                                        var CheckIntValue = int.TryParse(MatchedRule.SettingValue, out DelayBuffer);
                                        attendanceRule.DelayBuffer = DelayBuffer;
                                        break;
                                    default:
                                        break;
                                }
                            }

                        }
                        AttendanceRule.Add(attendanceRule);
                    }

                } while (false);
            }
            catch (Exception error)
            {
                throw error;
            }
            return AttendanceRule;
        }

        /// <summary>
        /// 程序执行时间测试
        /// </summary>
        /// <param name="dateBegin">开始时间</param>
        /// <param name="dateEnd">结束时间</param>
        /// <returns>返回(秒)单位,比如: 0.00239秒</returns>
        private double ExecDateDiff(DateTime dateBegin, DateTime dateEnd)
        {
            var ts1 = new TimeSpan(dateBegin.Ticks);
            var ts2 = new TimeSpan(dateEnd.Ticks);
            var ts3 = ts1.Subtract(ts2).Duration();
            //你想转的格式
            return ts3.TotalHours;
        }
    }

    
}