
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Share.Enum.ModuleEnum;
using Siger.Middlelayer.TpmRepository.Entities;
using Siger.Middlelayer.TpmRepository.Repositories.Interface;
using Siger.Middlelayer.TpmRepository.Request;
using Siger.Middlelayer.TpmRepository.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Siger.Middlelayer.TpmRepository.Repositories
{
    /// <summary>
	/// SigerAndonExpectionType
	/// </summary>
    internal class SigerAndonInfoRepository : TpmRepositoryBase<siger_andon_info>, ISigerAndonInfoRepository
    {
        private readonly ApiTpmDbContext _context;
        public SigerAndonInfoRepository(ApiTpmDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<ResponseAndon> GetData(RequestAndon condition, int projectid)
        {
            var start = condition.starttime;
            var end = condition.endtime;
            Expression<Func<siger_andon_info, bool>> funTime = f => true;
            if (start != 0 && end != 0 && start <= end)
            {
                funTime = f => f.create_time >= start && f.create_time <= end;
            }
            Expression<Func<siger_andon_info, bool>> funSection = f => true;
            if (condition.section != 0)
            {
                var sections = GetSonLevelSections(condition.section, projectid).Select(s => s.id).ToList();
                if (!sections.Any())
                {
                    sections.Add(condition.section);
                }
                funSection = f => sections.Contains(f.station);
            }
            Expression<Func<siger_andon_info, bool>> funExpection = f => true;
            if (condition.expection != 0)
            {
                var expections = GetExpectionSonLevel(condition.expection, projectid).Select(s => s.id).ToList();
                if (!expections.Any())
                {
                    expections.Add(condition.expection);
                }
                funExpection = f => expections.Contains(f.expection_type);
            }
            Expression<Func<siger_andon_info, bool>> funMachine = f => true;
            if (condition.machine != 0)
            {
                funMachine = f => f.machine.Equals(condition.machine);
            }
            Expression<Func<siger_andon_info, bool>> funStatus = f => true;
            if (condition.status != 0)
            {
                funStatus = f => f.status.Equals(condition.status);
            }
            Expression<Func<siger_andon_info, bool>> funStates = f => true;
            if (condition.states != null && condition.states.Any())
            {
                funStates = f => condition.states.Contains(f.status);
            }
            Expression<Func<siger_andon_info, bool>> funIds = f => true;
            if (condition.ids != null && condition.ids.Any())
            {
                funIds = f => condition.ids.Contains(f.id);
            }
            Expression<Func<siger_andon_info, bool>> funProduct = f => true;
            if (!string.IsNullOrEmpty(condition.product_code))
            {
                funProduct = f => f.product_code.Equals(condition.product_code);
            }

            Expression<Func<siger_andon_info, bool>> funWorkorder = f => true;
            if (!string.IsNullOrEmpty(condition.work_order))
            {
                funWorkorder = f => f.work_order == condition.work_order;
            }
            var predicate = funSection.And(funMachine).And(funStatus).And(funExpection).And(funTime).And(funStates).And(funIds).And(funProduct).And(funWorkorder);
            var query = from info in _context.siger_andon_info
                        where info.status != (int)RowState.Invalid && info.projectid.Equals(projectid)
                        orderby info.create_time descending
                        select info;
            var count = query.Count(predicate);
            var entities = query.Where(predicate).Skip((condition.page - 1) * condition.pagesize).Take(condition.pagesize).AsNoTracking().ToList();
            var model = new List<ResponseAndon>();
            foreach (var item in entities)
            {
                var expections = GetExpectionParent(item.expection_type, projectid).OrderBy(o => o.level).ToList();
                var data = Mapper<siger_andon_info, ResponseAndon>.Map(item);
                if (expections != null && expections.Any())
                {
                    if (expections.Count >= 3)
                    {
                        data.expection1 = expections[0].name;
                        data.expection2 = expections[1].name;
                        data.expection3 = expections[2].name;
                        data.usergroup = expections[2].usergroup;
                    }
                    if (expections.Count == 2)
                    {
                        data.expection1 = expections[0].name;
                        data.expection2 = expections[1].name;
                        data.usergroup = expections[1].usergroup;
                    }
                    if (expections.Count == 1)
                    {
                        data.expection1 = expections[0].name;
                        data.is_caloee = expections[0].is_caloee;
                        data.is_passprocess = expections[0].is_passprocess;
                    }
                }
                if (data.usergroup != 0)
                {
                    data.usergroup_name = _context.siger_project_usergroup.FirstOrDefault(f => f.projectid == projectid && f.status != 0 && f.id == data.usergroup)?.title ?? "";
                }
                var sections = GetParentLevelSections(item.station, projectid).Select(s => s.title).ToArray();
                if (sections != null && sections.Any())
                {
                    data.station_name = string.Join("-", sections.Reverse());
                }
                var machine = _context.siger_project_machine.FirstOrDefault(f => f.id.Equals(data.machine) && f.projectid == projectid);
                if (machine != null)
                {
                    data.machine_name = machine.title;
                }
                data.creator_name = GetUserByMid(item.creator)?.name ?? "";
                data.handler_name = GetUserByMid(item.handler)?.name ?? "";
                long now = UnixTimeHelper.GetNow();
                //安灯触发直到处理完成所花费的时间
                if (item.status > (int)AndonState.Complete)
                {
                    var andon_cost_time = Convert.ToInt32(item.complete_time - item.create_time);
                    if (andon_cost_time > 0)
                    {
                        data.andon_cost_time = UnixTimeHelper.GetTimeBySecond(andon_cost_time);
                    }
                    else
                    {
                        data.andon_cost_time = UnixTimeHelper.GetTimeBySecond((int)(now - item.create_time));
                    }
                }
                //安灯开始处理直到安灯处理完成所花费的时间
                var handle_cost_time = Convert.ToInt32(item.complete_time - item.handle_time);
                if (handle_cost_time > 0)
                {
                    data.handle_cost_time = UnixTimeHelper.GetTimeBySecond(handle_cost_time);
                }
                //安灯触发直到开始处理的时间
                if (item.create_time != 0)
                {
                    var unresponse_time = Convert.ToInt32((item.handle_time == 0 ? now : item.handle_time) - item.create_time);
                    if (unresponse_time > 0)
                    {
                        data.unresponse_time = UnixTimeHelper.GetTimeBySecond(unresponse_time);
                    }
                }
                //安灯开始处理直到处理完成的时间
                if (item.handle_time != 0)
                {
                    var unhandle_time = Convert.ToInt32((item.complete_time == 0 ? now : item.complete_time) - item.handle_time);
                    if (unhandle_time > 0)
                    {
                        data.unhandle_time = UnixTimeHelper.GetTimeBySecond(unhandle_time);
                    }
                }
                //异常触发直到安灯确认所花费的时间
                if (item.complete_time != 0)
                {
                    var unfinish_time = Convert.ToInt32((item.approve_time == 0 ? now : item.approve_time) - item.complete_time);
                    if (unfinish_time > 0)
                    {
                        data.unfinish_time = UnixTimeHelper.GetTimeBySecond(unfinish_time);
                    }
                }
                else if (data.is_passprocess == 1 && item.complete_time == 0)
                {
                    var unfinish_time = Convert.ToInt32(now - item.create_time);
                    if (unfinish_time > 0)
                    {
                        data.unfinish_time = UnixTimeHelper.GetTimeBySecond(unfinish_time);
                    }
                }
                //异常触发直到安灯确认所花费的时间
                if (item.abnormal_time != 0)
                {
                    var untrigger_time = Convert.ToInt32((item.create_time == 0 ? now : item.create_time) - item.abnormal_time);
                    if (untrigger_time > 0)
                    {
                        data.untrigger_time = UnixTimeHelper.GetTimeBySecond(untrigger_time);
                    }
                }
                if (!string.IsNullOrEmpty(item.product_code))
                {
                    var product = _context.siger_project_product.FirstOrDefault(f => f.projectid == projectid && f.status != 0 && f.code.Equals(item.product_code));
                    if (product != null)
                    {
                        data.product_code = product.code;
                        data.product_name = product.name;
                    }
                }
                data.cost_time = (data.approve_time == 0 ? now : data.approve_time) - data.create_time;
                //临时方案（请更改） 
                var details = _context.siger_andon_info_detail.Where(f => f.projectid == projectid && f.status != 0 && f.level == 0 && f.andon_id == item.id).ToList();
                data.approver_name = details.FirstOrDefault(f => f.status == (int)AndonState.Approve || f.status == (int)AndonState.Com_Approve || f.status == (int)AndonState.Recovery)?.user ?? "";
                data.remark = details.FirstOrDefault(f => f.status == (int)AndonState.Complete)?.remark ?? "";//pd requirement
                data.completer_name = details.FirstOrDefault(f => f.status == (int)AndonState.Complete)?.user ?? data.handler_name;
                model.Add(data);
            }
            return new PagedCollectionResult<ResponseAndon>(model, count);
        }
        /// <summary>
        /// 计算未确认以及之后的安灯时间
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public ResponseAndonInfoByMachine GetCostTimeByMachineid(RequestAndon condition, int projectid)
        {
            var start = condition.starttime;
            var end = condition.endtime;
            var ret = new ResponseAndonInfoByMachine();
            var now = UnixTimeHelper.GetNow();
            var query = _context.siger_andon_info.Where(f => f.projectid == projectid && f.status != (int)RowState.Invalid && f.machine.Equals(condition.machine) && f.create_time >= start && f.create_time <= end);

            //未复线的安灯
            long cost = query.Where(f => f.status < (int)AndonState.CancleAbnormal).Select(s => new { time = (s.complete_time == 0 ? now : s.complete_time) - s.create_time })?.Sum(s => s.time) ?? 0;
            //cost += query.Where(f => f.status >= (int)AndonState.Complete).Select(s => new { time = s.complete_time - s.create_time })?.Sum(s => s.time) ?? 0;
            ret.cost_time = (cost / 60).ToStr();
            ret.andon_count = query.Count();
            return ret;
        }
        public int GetCountByType(AndonState state, int projectid)
        {
            var status = (int)state;
            var query = from info in _context.siger_andon_info
                        where info.status.Equals(status) && info.projectid.Equals(projectid)
                        orderby info.create_time descending
                        select info;
            return query.Count();
        }
        /// <summary>
        /// 工单生成器
        /// </summary>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public string WorkOrderGenerator(int projectid)
        {
            var ret = string.Empty;
            var time = $"A{DateTime.Now.ToString("yyyyMMdd")}";
            var infomodel = _context.siger_andon_info.Where(f => f.projectid.Equals(projectid) && f.work_order.StartsWith(time));
            var no = 1;
            if (infomodel.Any())
            {
                var maxid = infomodel.Max(m => m.id);
                var max = _context.siger_andon_info.First(f => f.id == maxid).work_order;
                var maxparams = max.Split('_');
                if (maxparams.Length == 2)
                {
                    no = maxparams[1].ToInt() + 1;
                }
            }
            ret = $"{time}_{no}";
            return ret;
        }
        public List<ResponseAndonGroupCount> GetAndonGroupCount(int project_id, long start, long end)
        {
            var ret = new List<ResponseAndonGroupCount>();
            var query = from info in _context.siger_andon_info
                        join exp in _context.siger_andon_expection_type on info.expection_type equals exp.id
                        //join exp in _context.siger_andon_expection_type on info.expection_type equals exp.id into temp
                        //from exp in temp.DefaultIfEmpty()
                        join gro in _context.siger_project_usergroup on exp.usergroup equals gro.id
                        where info.projectid == project_id && info.status > (int)AndonState.Abnormal && info.create_time >= start && info.create_time <= end && info.status < (int)AndonState.Approve
                        select new ResponseAndonGroupCount
                        {
                            group_id = gro.id,
                            group_name = gro.title,
                            handling_count = info.status == (int)AndonState.Handling ? 1 : 0,
                            unhandle_count = info.status == (int)AndonState.WaitHandle ? 1 : 0,
                            wait_count = info.status == (int)AndonState.Complete ? 1 : 0,
                        };
            foreach (var item in query.ToList())
            {
                if (ret.Any(f => f.group_id == item.group_id))
                {
                    var data = ret.First(f => f.group_id == item.group_id);
                    data.handling_count += item.handling_count;
                    data.unhandle_count += item.unhandle_count;
                    data.wait_count += item.wait_count;
                    continue;
                }
                ret.Add(new ResponseAndonGroupCount
                {
                    group_id = item.group_id,
                    group_name = item.group_name,
                    handling_count = item.handling_count,
                    unhandle_count = item.unhandle_count,
                    wait_count = item.wait_count
                });
            }
            return ret;
        }
        public List<GetAndonDashboradDetail> GetAndonDashboradDetail(int project_id, long start, long end)
        {
            var now = UnixTimeHelper.GetNow();
            var query = from f in _context.siger_andon_info
                        join ex in _context.siger_andon_expection_type on f.expection_type equals ex.id into temp
                        from ex in temp.DefaultIfEmpty()
                        where f.status != 0 && f.status != 1 && f.projectid == project_id && f.status <= (int)AndonState.Complete
                        && f.create_time >= start && f.create_time <= end
                        select new GetAndonDashboradDetail
                        {
                            order = f.work_order,
                            create_time = f.create_time,
                            location_value = f.station,
                            expection_value = f.expection_type,
                            //坑
                            //cost_time = f.complete_time == 0 ? (now - f.create_time) : (f.complete_time - f.create_time),
                            cost_time = f.approve_time == 0 ? (now - f.create_time) : (f.approve_time - f.create_time),
                            status_value = f.status,
                            handler_value = f.handler,
                            errorlevel = ex.errorlevel,
                            parent_expection_value = ex.parent,
                            group_value = ex.usergroup,
                            expection = ex.name
                        };
            var sections = _context.siger_project_level_section.Where(f => f.projectid == project_id && f.status != 0 && f.parentid != 0).ToList();
            var groups = _context.siger_project_usergroup.Where(f => f.projectid == project_id && f.status != 0).ToList();
            var users = _context.siger_project_user.Where(f => f.projectid == project_id && f.status != 0).ToList();
            var expections = _context.siger_andon_expection_type.Where(f => f.projectid == project_id && f.status != 0).ToList();
            var ret = query.ToList();
            foreach (var item in ret)
            {
                item.expection = (expections.FirstOrDefault(f => f.id == item.parent_expection_value)?.name + "-" ?? "") + item.expection;
                var parent = expections.FirstOrDefault(f => f.id == item.parent_expection_value);
                if (parent != null && parent.level == 2)
                {
                    item.expection = (expections.FirstOrDefault(f => f.id == parent.parent)?.name + "-" ?? "") + parent.name;
                }
                if (parent == null)//design by pm
                {
                    item.expection = item.expection.TrimStart('-');
                }
                item.status = EnumHelper.GetEnumDesc((AndonState)item.status_value);
                item.handler = users.FirstOrDefault(f => f.mid == item.handler_value)?.name ?? "";
                item.group = groups.FirstOrDefault(f => f.id == item.group_value)?.title ?? "";
                var location = sections.FirstOrDefault(f => f.id == item.location_value);
                if (location != null)
                {
                    item.location = (sections.FirstOrDefault(f => f.id == location.parentid)?.title + "-" ?? "") + location.title;
                }
            }
            return ret;
        }
        /// <summary>
        /// 安灯处理
        /// </summary>
        /// <param name="req"></param>
        /// <param name="pid"></param>
        /// <param name="cid"></param>
        /// <param name="uid"></param>
        /// <returns></returns>
        public bool HandleAndon(RequestHandleAndon req, int pid, int cid, int uid)
        {
            var usergroupid = _context.siger_project_user.FirstOrDefault(f => f.mid == uid)?.usergroupid ?? "0";
            var nowtime = UnixTimeHelper.GetNow();
            var status = 0;
            var model = _context.siger_andon_info.FirstOrDefault(f => f.status != (int)RowState.Invalid && f.status < (int)AndonState.Approve && f.projectid.Equals(pid) && f.id.Equals(req.id));
            if (model == null)
            {
                throw new BadRequestException(TpmEnum.AndonNotFound);
            }
            model.status = req.type;
            model.cruent_level = 1;
            model.is_shutdown = req.is_shutdown.ToInt();
            //插入一笔历史记录
            var username = GetUserByMid(uid)?.name ?? "";
            _context.siger_andon_info_detail.Add(new siger_andon_info_detail
            {
                andon_id = model.id,
                createtime = nowtime,
                projectid = pid,
                status = req.type,
                user = username,
                remark = req.remark
            });
            //签到和解除责任岗判断
            if (req.type == (int)AndonState.Handling || req.type == (int)AndonState.Complete)
            {
                var expection = _context.siger_andon_expection_type.FirstOrDefault(f => f.projectid == pid && f.id == model.expection_type);
                if (expection == null)
                {
                    throw new BadRequestException(TpmEnum.ExpectionNotFound);
                }
                if (usergroupid.ToInt() != expection.usergroup && usergroupid.ToInt() != expection.second_usergroup)
                {
                    switch (req.type)
                    {
                        case (int)AndonState.Handling:
                            throw new BadRequestException(TpmEnum.UsergroupNotInHandlingExpection);
                        case (int)AndonState.Complete:
                            throw new BadRequestException(TpmEnum.UsergroupNotInCompleteExpection);
                        default:
                            break;
                    }
                }
            }
            //换型损失拦截无有效产品
            if (req.type == (int)AndonState.Recovery)
            {
                var expection = _context.siger_andon_expection_type.FirstOrDefault(f => f.projectid == pid && f.id == model.expection_type);
                if (expection != null && expection.is_passprocess == 1 && expection.is_caloee == 1 && string.IsNullOrEmpty(req.product_code))//换形
                {
                    throw new BadRequestException(TpmEnum.ProductCodeInvalid);
                }
            }
            switch (req.type)
            {
                case (int)AndonState.Approve:
                    model.expection_type = req.expection;
                    status = (int)AndonState.Approve;
                    model.approve_time = nowtime;
                    break;
                case (int)AndonState.Complete:
                    status = (int)AndonState.Complete;
                    model.complete_time = nowtime;
                    model.remark = req.remark;
                    model.expection_type = req.expection;
                    break;
                case (int)AndonState.Handling:
                    model.handler = uid;
                    model.handle_time = nowtime;
                    status = (int)AndonState.Handling;
                    break;
                case (int)AndonState.CanNotRecovery:
                    status = (int)AndonState.Handling;
                    model.complete_time = 0;
                    break;
                default:
                    status = req.type;
                    model.approve_time = nowtime;
                    model.product_code = req.product_code;
                    break;
            }
            if (!string.IsNullOrEmpty(req.remark))
            {
                model.remark = req.remark;
            }
            model.status = status;
            var expectiondata = _context.siger_andon_expection_type.FirstOrDefault(f => f.id == model.expection_type);
            if ((expectiondata?.is_passprocess ?? 0) == 1)
            {
                model.complete_time = nowtime;
            }
            //计划停机
            if (req.start != 0 && req.end != 0 && (expectiondata?.is_caloee ?? 1) == 0)
            {
                model.approve_time = 0;
                var tempdata = _context.siger_andon_info.Where(f => f.expection_type == model.expection_type && f.machine == model.machine).ToList();
                if (tempdata.Any())
                {
                    var max = tempdata.Max(m => m.approve_time);
                    if (max > req.start)
                    {
                        throw new BadRequestException(TpmEnum.StopMachineExist);
                    }
                }
                if (tempdata.Any(f => f.status < (int)AndonState.Approve))
                {
                    throw new BadRequestException(TpmEnum.StopMachineExist);
                }
                model.create_time = req.start;
                model.handle_time = req.start;
                model.approve_time = req.end;
                model.complete_time = req.end;
            }
            _context.siger_andon_info.Update(model);
            return true;
        }


        public List<siger_project_auto_calculation_data_ttlEx> GetOee(DateTime start, DateTime end, List<int> sections)
        {
            return _context.siger_project_auto_calculation_data_hour_ttl.Where(f => f.status != 0
            && f.ratetype == DashboardTotalRate.OEE && f.starttime >= start && f.endtime <= end && sections.Contains(f.section)).ToList();
        }

        public IEnumerable<ResponseAndonDetials> AndonDetials(int project_id, long start, long end,int andontstate)
        {
            var now = UnixTimeHelper.GetNow();
            var query = from f in _context.siger_andon_info
                        join ex in _context.siger_andon_expection_type on f.expection_type equals ex.id into extemp
                        from ex in extemp.DefaultIfEmpty()
                        join usg in _context.siger_project_usergroup on ex.usergroup equals usg.id into usgtemp
                        from usg in usgtemp.DefaultIfEmpty()
                        join s in _context.siger_project_section on usg.sectionid equals s.id into stemp
                        from se in stemp.DefaultIfEmpty()
                        //join s in _context.siger_project_level_section on f.station equals s.id
                        //join ls in _context.siger_project_level_section on s.parentid equals ls.id
                       // join u in _context.siger_project_user on f.handler equals u.mid
                        where f.projectid == project_id && f.create_time >= start && f.create_time <= end && f.status > andontstate && f.status< (int)AndonState.CancleAbnormal
                        select new ResponseAndonDetials
                        {
                            id=f.id,
                            section = se != null ? se.id : 0,
                            sectionTitle = se != null? se.title:"",
                            station=usg!=null?usg.id:0,
                            stationTitle=usg!=null?usg.title:"",
                            create_time = f.create_time,
                            handle_time = f.handle_time,
                            approve_time = f.approve_time,
                            complete_time = f.complete_time,
                            expectype=f.expection_type,
                            status=f.status,
                            creater=f.creator,
                            hanlder=f.handler,
                          
                           // username=$"{u.name}"
                        };
            var data = query.GroupBy(g => g.id).Select(f => f.FirstOrDefault()).ToList();
            foreach (var d in data)
            {
                var details = _context.siger_andon_info_detail.Where(f => f.projectid == project_id && f.status != 0 && f.level == 0 && f.andon_id == d.id).ToList();
                d.approver = details.FirstOrDefault(f => f.status == (int)AndonState.Approve || f.status == (int)AndonState.Com_Approve || f.status == (int)AndonState.Recovery)?.user ?? "";

                d.complater = details.FirstOrDefault(f => f.status == (int)AndonState.Complete)?.user ?? "";

            }
            return data;
   
        }
    }
}
