using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
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.Data.Tpm;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.TpmRepository.Entities;
using Siger.Middlelayer.TpmRepository.Repositories.Interface;

namespace Siger.Middlelayer.TpmRepository.Repositories
{
    internal class PlanItemRepository : TpmRepositoryBase<siger_project_plan_item>, IPlanItemRepository
    {
        private readonly ApiTpmDbContext _context;
        public PlanItemRepository(ApiTpmDbContext context) : base(context)
        {
            _context = context;
        }

        public IEnumerable<GetListPlanItem> GetOnePlanItem(int planId, int projectid)
        {
            var query = from t in _context.siger_project_plan_item
                        where t.projectid == projectid && t.status > 0
                        join plan in _context.siger_project_plan on t.id equals plan.itemid
                        where plan.status > 0 && plan.projectid == projectid
                        select new GetListPlanItem
                        {
                            id = plan.id > 0 ? plan.id : 0,
                            type = t.type,
                            typeid = t.typeid,
                            machineid = t.machineid,
                            content = t.content,
                            value_type = t.value_type,
                            mode = t.mode,
                            unit = t.unit,
                            up_limit = t.up_limit,
                            lower_limit = t.lower_limit,
                            severity_level = t.severity_level,
                            failure_mode = t.failure_mode,
                            work_instruction_url = t.work_instruction_url,
                            result_demo_url = t.result_demo_url,
                            standard_time = t.standard_time,
                            instruction_cycle = t.instruction_cycle,
                            create_mid = t.create_mid,
                            create_time = t.create_time,
                            remark = t.remark,
                            work_instruction_name = t.work_instruction_name,
                            itemid = plan.itemid,
                            first_instruction_time = plan.first_instruction_time,
                            instruction_mid = plan.instruction_mid,
                            count = plan.count,
                            date_rang = plan.date_rang,
                            endtime = plan.endtime,
                            starttime = plan.starttime,
                            maintain_sparepart = t.maintain_sparepart,
                            maintain_tool = t.maintain_tool,
                            hit_item = t.hit_item,
                            maintain_method = t.maintain_method,
                            faulttype = t.faulttype
                        };

            Expression<Func<GetListPlanItem, bool>> itemidExpression = q => true;
            if (planId > 0)
            {
                itemidExpression = q => q.id == planId;
            }

            return query.Where(itemidExpression).ToList();
        }

        public IPagedCollectionResult<GetListSearchPlan> GetPagedlist(int projectId, int page, int pagesize)
        {
            var rowState = (int)RowState.Valid;
            var queryList = from t in _context.siger_project_plan_item
                            where t.status == rowState && t.projectid == projectId
                            join plan in _context.siger_project_plan on t.id equals plan.itemid
                            where plan.projectid == projectId && plan.status == rowState
                            join machine in _context.siger_project_machine on t.machineid equals machine.id
                            where machine.projectid == projectId && machine.status == rowState
                            join u in _context.siger_project_user on plan.instruction_mid.Split(new char[] { ',' },
                                StringSplitOptions.RemoveEmptyEntries)[0].ToInt() equals u.mid into uu
                            from users in uu.DefaultIfEmpty()
                            select new GetListSearchPlan
                            {
                                id = t.id,
                                type = t.type,
                                typeid = t.typeid,
                                machineid = t.machineid,
                                content = t.content,
                                remark = t.remark,
                                value_type = t.value_type,
                                mode = t.mode,
                                unit = t.unit,
                                up_limit = t.up_limit,
                                lower_limit = t.lower_limit,
                                severity_level = t.severity_level,
                                failure_mode = t.failure_mode,
                                work_instruction_url = t.work_instruction_url,
                                result_demo_url = t.result_demo_url,
                                standard_time = t.standard_time,
                                instruction_cycle = t.instruction_cycle,
                                create_mid = t.create_mid,
                                create_time = t.create_time,
                                work_instruction_name = t.work_instruction_name,
                                planid = plan.id,
                                name = users.name,
                                machinetitle = machine.title,
                                first_instruction_time = string.IsNullOrEmpty(plan.first_instruction_time)
                                    ? "-"
                                    : UnixTimeHelper.ConvertStringDateTime(plan.first_instruction_time)
                                        .ToString(ParameterConstant.DateFormat),
                                department = users.sectionid > 0 ? users.sectionid : 0,
                                instruction_mid = plan.instruction_mid
                            };

            var totalCount = queryList.Count();
            var entities = queryList.Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<GetListSearchPlan>(entities, totalCount);
        }

        public int GetPlanIdMax()
        {
            var count = _context.siger_project_plan.Count();
            return count > 0 ? _context.siger_project_plan.Max(t => t.id) : 0;
        }

        public int GetItemIdMax()
        {
            var count = _context.siger_project_plan_item.Count();
            return count > 0 ? _context.siger_project_plan_item.Max(t => t.id) : 0;
        }

        public int GetTimeIdMax()
        {
            var count = _context.siger_project_plan_time.Count();
            return count > 0 ? _context.siger_project_plan_time.Max(t => t.id) : 0;
        }

        #region APP接口
        public IEnumerable<GetAppPlan> GetMachinePlans(int nowtime, List<int> machineIDArr, int projectId, int userId)
        {
            var tolerances = _context.siger_project_plan_report_tolerance.Where(q => q.projectid == projectId && q.status == (int)RowState.Valid && q.mode == 0);
            var queryPlans = from plan in _context.siger_project_plan
                             join item in _context.siger_project_plan_item on plan.itemid equals item.id
                             join machine in _context.siger_project_machine on plan.machineid equals machine.id
                             join time in _context.siger_project_plan_time on plan.id equals time.planid
                             where machineIDArr.Contains(plan.machineid) && plan.status != 0 && plan.projectid == projectId
                             && time.information > 1 && time.status != 0
                             && machine.projectid == projectId && machine.status != 0
                             select new GetAppPlan
                             {
                                 id = item.id,
                                 type = item.type,
                                 typeid = item.typeid,
                                 machineid = item.machineid,
                                 machine_name = machine.title,
                                 content = item.content,
                                 remark = item.remark,
                                 value_type = item.value_type,
                                 mode = item.mode,
                                 unit = item.unit,
                                 up_limit = item.up_limit,
                                 lower_limit = item.lower_limit,
                                 severity_level = item.severity_level,
                                 failure_mode = item.failure_mode,
                                 work_instruction_url = item.work_instruction_url,
                                 result_demo_url = item.result_demo_url,
                                 standard_time = item.standard_time,
                                 instruction_cycle = item.instruction_cycle,
                                 create_mid = item.create_mid,
                                 create_time = item.create_time,
                                 work_instruction_name = item.work_instruction_name,
                                 planid = plan.id > 0 ? plan.id : 0,
                                 instruction_mid = time.instruction_mid > 0 ? time.instruction_mid : 0,
                                 instruction_time = time.instruction_time > 0 ? time.instruction_time : 0,
                                 ptimeid = time.id,
                                 maintain_sparepart = item.maintain_sparepart ?? "",
                                 maintain_tool = item.maintain_tool ?? "",
                                 hit_item = item.hit_item ?? "",
                                 maintain_method = item.maintain_method ?? "",
                                 instruction_start = time.instruction_time,
                                 instruction_end = time.instruction_time,
                             };
            
            if(tolerances.Any())
            {
                var list = new List<GetAppPlan>();
                foreach (var plan in queryPlans.ToList())
                {
                    var entity = Mapper<GetAppPlan, GetAppPlan>.Map(plan);
                    var tolerance = tolerances.FirstOrDefault(q => q.type == plan.instruction_cycle);
                    if(tolerance != null)
                    {
                        entity.instruction_start = entity.instruction_time - tolerance.space_time * 86400;
                        entity.instruction_end = entity.instruction_time + tolerance.space_time * 86400;
                        entity.space_time = tolerance.space_time;
                    }
                    list.Add(entity);
                }
                return list.Where(f => f.instruction_start <= nowtime && f.instruction_end >= nowtime);
            }
            else
            {
                return queryPlans.Where(f => f.instruction_start <= nowtime);
            }
        }

        public IEnumerable<GetAppPlan> GetPlanHistoryListEx(int endTime, List<int> machineIDArr, int projectId, int userId)
        {
            var plans = _context.siger_project_plan.Where(f => machineIDArr.Contains(f.machineid) && f.status != 0 && f.projectid == projectId).Select(s => s.id).ToList();
            var finishedPlan = _context.siger_project_plan_time.Where(f => plans.Contains(f.planid) && f.status != 0 && f.information == 1).ToList().Select(s => s.planid).Distinct();
            var records = _context.siger_project_plan_record.Where(f => finishedPlan.Contains(f.planid));
            var queryList = from record in records
                            join plan in _context.siger_project_plan on record.planid equals plan.id
                            join t in _context.siger_project_plan_item on plan.itemid equals t.id
                            join ptime in _context.siger_project_plan_time on plan.id equals ptime.planid
                            where ptime.projectid == projectId && ptime.status > 0 &&
                                    ptime.information == (int)PlanStatus.Normal
                            select new GetAppPlan
                            {
                                id = t.id,
                                type = t.type,
                                typeid = t.typeid,
                                machineid = t.machineid,
                                content = t.content,
                                remark = t.remark,
                                value_type = t.value_type,
                                mode = t.mode,
                                unit = t.unit,
                                up_limit = t.up_limit,
                                lower_limit = t.lower_limit,
                                severity_level = t.severity_level,
                                failure_mode = t.failure_mode,
                                work_instruction_url = t.work_instruction_url,
                                result_demo_url = t.result_demo_url,
                                standard_time = t.standard_time,
                                instruction_cycle = t.instruction_cycle,
                                create_time = t.create_time,
                                work_instruction_name = t.work_instruction_name,
                                planid = plan.id,
                                instruction_mid = ptime.instruction_mid,
                                instruction_time = ptime.instruction_time,
                                actual_mid = record.actual_mid,
                                create_mid = record.create_mid,
                                ptimeid = ptime.id,
                                maintain_sparepart = t.maintain_sparepart ?? "",
                                maintain_tool = t.maintain_tool ?? "",
                                hit_item = t.hit_item ?? "",
                                maintain_method = t.maintain_method ?? "",
                                keep_remark = ptime.keep_remark
                            };
            return queryList.GroupBy(t => t.ptimeid).Select(t => t.FirstOrDefault()).ToList();
        }

        public IEnumerable<GetAppPlan> GetPlanListByMid(int nowtime, List<int> machineIDArr, int projectId, int userId)
        {
            var rowState = (int)RowState.Valid;
            var queryList = from t in _context.siger_project_plan_item
                            join plan in _context.siger_project_plan on t.id equals plan.itemid
                            join machine in _context.siger_project_machine on t.machineid equals machine.id
                            join ptime in _context.siger_project_plan_time on plan.id equals ptime.planid
                            join inf in _context.siger_project_plan_report_tolerance on plan.instruction_cycle equals inf.type into temp
                            from inf in temp.DefaultIfEmpty()
                            where ptime.projectid == projectId && ptime.status == rowState && machine.status == rowState &&
                                  ptime.information > 1 &&
                                  //ptime.instruction_time < nowtime &&
                                  (machineIDArr.Contains(machine.id) || ptime.instruction_mid == userId) &&
                                  t.status == rowState && t.projectid == projectId
                                  && inf.projectid == projectId && inf.status != 0 && inf.mode == 0
                            select new GetAppPlan
                            {
                                id = t.id,
                                type = t.type,
                                typeid = t.typeid,
                                machineid = t.machineid,
                                machine_name = machine.title,
                                content = t.content,
                                remark = t.remark,
                                value_type = t.value_type,
                                mode = t.mode,
                                unit = t.unit,
                                up_limit = t.up_limit,
                                lower_limit = t.lower_limit,
                                severity_level = t.severity_level,
                                failure_mode = t.failure_mode,
                                work_instruction_url = t.work_instruction_url,
                                result_demo_url = t.result_demo_url,
                                standard_time = t.standard_time,
                                instruction_cycle = t.instruction_cycle,
                                create_mid = t.create_mid,
                                create_time = t.create_time,
                                work_instruction_name = t.work_instruction_name,
                                planid = plan.id > 0 ? plan.id : 0,
                                instruction_mid = ptime.instruction_mid > 0 ? ptime.instruction_mid : 0,
                                instruction_time = ptime.instruction_time > 0 ? ptime.instruction_time : 0,
                                ptimeid = ptime.id,
                                maintain_sparepart = t.maintain_sparepart ?? "",
                                maintain_tool = t.maintain_tool ?? "",
                                hit_item = t.hit_item ?? "",
                                maintain_method = t.maintain_method ?? "",
                                instruction_start = ptime.instruction_time - inf.space_time * 86400,
                                instruction_end = ptime.instruction_time + inf.space_time * 86400,
                                space_time = inf.space_time
                            };
            Expression<Func<GetAppPlan, bool>> userExpression = q => true;
            if (userId > 0)
            {
                userExpression = q => q.instruction_mid == userId;
            }
            Expression<Func<GetAppPlan, bool>> nowExpression = q => q.instruction_start <= nowtime;
            var predicate = userExpression.And(nowExpression);
            var dataList = queryList.Where(predicate).AsNoTracking().ToList();
            return dataList.GroupBy(t => t.ptimeid).Select(t => t.FirstOrDefault()).ToList();
        }

        /// <summary>
        /// 查询历史计划维护 兼容被禁用的已执行记录
        /// </summary>
        /// <returns></returns>
        public IEnumerable<GetAppPlan> GetPlanHistoryListByMid(int endTime, List<int> machineIDArr, int projectId, int userId)
        {
            var ret = new List<GetAppPlan>();
            var recordQuery = from record in _context.siger_project_plan_record
                              where record.status != 0 && record.projectid == projectId
                              select record;
            var timeQuery = from time in _context.siger_project_plan_time
                            where time.status != 0 && time.information == 1 && time.projectid == projectId
                            select time;
            var planQuery = from plan in _context.siger_project_plan
                            where plan.status != 0 && plan.projectid == projectId
                            select plan;
            var itemQuery = from item in _context.siger_project_plan_item
                            where item.status != 0 && item.projectid == projectId
                            select item;

            foreach (var item in recordQuery.ToList())
            {

                var itemid = planQuery.FirstOrDefault(f => f.id == item.planid)?.itemid ?? 0;
                var t = itemQuery.FirstOrDefault(f => f.id == itemid);
                var time = timeQuery.FirstOrDefault(f => f.id == item.plan_time_id);
                if (t != null)
                {
                    if (!machineIDArr.Contains(t.machineid))
                    {
                        continue;
                    }
                    //if (item.create_time > endTime)
                    //{
                    //    continue;
                    //}
                    if (item.actual_mid != userId || item.create_mid != userId)
                    {
                        continue;
                    }
                    var data = new GetAppPlan
                    {
                        id = t.id,
                        type = t.type,
                        typeid = t.typeid,
                        machineid = t.machineid,
                        content = t.content,
                        remark = t.remark,
                        value_type = t.value_type,
                        mode = t.mode,
                        unit = t.unit,
                        up_limit = t.up_limit,
                        lower_limit = t.lower_limit,
                        severity_level = t.severity_level,
                        failure_mode = t.failure_mode,
                        work_instruction_url = t.work_instruction_url,
                        result_demo_url = t.result_demo_url,
                        standard_time = t.standard_time,
                        instruction_cycle = t.instruction_cycle,
                        create_time = t.create_time,
                        work_instruction_name = t.work_instruction_name,
                        planid = item.planid,
                        instruction_mid = time?.instruction_mid ?? 0,
                        instruction_time = time?.instruction_time ?? 0,
                        actual_mid = item.actual_mid,
                        create_mid = item.create_mid,
                        ptimeid = time?.id ?? 0,
                        maintain_sparepart = t.maintain_sparepart ?? "",
                        maintain_tool = t.maintain_tool ?? "",
                        hit_item = t.hit_item ?? "",
                        maintain_method = t.maintain_method ?? ""
                    };
                    ret.Add(data);
                }
            }
            return ret.GroupBy(t => t.ptimeid).Select(t => t.FirstOrDefault()).ToList();
        }

        public IEnumerable<GetAppPlan> GetPlanListByMachineID(int nowtime, int machineID, int projectId, int userId)
        {
            var rowState = (int)RowState.Valid;
            var queryList = (from t in _context.siger_project_plan_item
                             where t.status == rowState && t.projectid == projectId
                             join plan in _context.siger_project_plan on t.id equals plan.itemid
                             join ptime in _context.siger_project_plan_time on plan.id equals ptime.planid
                             join inf in _context.siger_project_plan_report_tolerance on plan.instruction_cycle equals inf.type into temp
                             from inf in temp.DefaultIfEmpty()
                             where ptime.projectid == projectId && ptime.status == rowState && ptime.information != 1
                                   //&& ptime.instruction_time < nowtime 
                                   && plan.machineid == machineID
                                   && inf.projectid == projectId && inf.status != 0 && inf.mode == 0
                             select new GetAppPlan
                             {
                                 id = t.id,
                                 ptimeid = ptime.id,
                                 planid = plan.id,
                                 type = t.type,
                                 typeid = t.typeid,
                                 machineid = t.machineid,
                                 content = t.content,
                                 remark = t.remark,
                                 value_type = t.value_type,
                                 mode = t.mode,
                                 unit = t.unit,
                                 up_limit = t.up_limit,
                                 lower_limit = t.lower_limit,
                                 severity_level = t.severity_level,
                                 failure_mode = t.failure_mode,
                                 work_instruction_url = t.work_instruction_url,
                                 result_demo_url = t.result_demo_url,
                                 standard_time = t.standard_time,
                                 instruction_cycle = t.instruction_cycle,
                                 create_mid = t.create_mid,
                                 create_time = t.create_time,
                                 work_instruction_name = t.work_instruction_name,
                                 instruction_mid = ptime.instruction_mid,
                                 instruction_time = ptime.instruction_time,
                                 maintain_sparepart = t.maintain_sparepart,
                                 maintain_tool = t.maintain_tool,
                                 keep_remark = ptime.keep_remark ?? "",
                                 hit_type = ptime.hit_type,
                                 hit_item = t.hit_item ?? "",
                                 maintain_method = t.maintain_method ?? "",
                                 instruction_start = ptime.instruction_time - inf.space_time * 86400,
                                 instruction_end = ptime.instruction_time + inf.space_time * 86400,
                                 space_time = inf.space_time
                             }).GroupBy(t => t.ptimeid).Select(t => t.FirstOrDefault()).ToList();

            return queryList.Where(f => f.instruction_start < nowtime);
        }

        /// <summary>
        /// 查询历史执行具体项点(今日) 兼容被禁用的已执行记录
        /// </summary>
        /// <returns></returns>
        public IEnumerable<GetAppPlans> GetPlanHistory(int Time, int machineID, int projectId, int userId)
        {
            var rowState = (int)RowState.Valid;
            var queryList = (from t in _context.siger_project_plan_item
                             where t.status == rowState && t.projectid == projectId
                             join plan in _context.siger_project_plan on t.id equals plan.itemid
                             join machine in _context.siger_project_machine on t.machineid equals machine.id
                             join ptime in _context.siger_project_plan_time on plan.id equals ptime.planid
                             join record in _context.siger_project_plan_record on ptime.id equals record.plan_time_id into r
                             from record in r.DefaultIfEmpty()
                             join u in _context.siger_project_user on record.actual_mid equals u.mid into uu
                             from users in uu.DefaultIfEmpty()
                             where ptime.projectid == projectId && ptime.status > 0 && machine.status == 1 && ptime.information == 1 &&
                             record.create_time >= Time && machine.id == machineID
                             select new GetAppPlans
                             {
                                 id = t.id,
                                 type = t.type,
                                 typeid = t.typeid,
                                 machineid = t.machineid,
                                 content = t.content,
                                 remark = t.remark,
                                 value_type = t.value_type,
                                 mode = t.mode,
                                 unit = t.unit,
                                 up_limit = t.up_limit,
                                 lower_limit = t.lower_limit,
                                 severity_level = t.severity_level,
                                 failure_mode = t.failure_mode,
                                 work_instruction_url = t.work_instruction_url,
                                 result_demo_url = t.result_demo_url,
                                 standard_time = record.actual_standard_time,
                                 instruction_cycle = t.instruction_cycle,
                                 create_time = t.create_time,
                                 actual_time = record.create_time,
                                 work_instruction_name = t.work_instruction_name,
                                 planid = plan.id,
                                 ptimeid = ptime.id,
                                 instruction_mid = ptime.instruction_mid,
                                 instruction_time = ptime.instruction_time,
                                 actual_mid = record.actual_mid,
                                 create_mid = record.create_mid,
                                 username = users.name ?? "",
                                 sparepartouts = record.sparepartout,
                                 imgurl = record.imgurl,
                                 value = record.value,
                                 maintain_sparepart = t.maintain_sparepart,
                                 maintain_tool = t.maintain_tool,
                                 keep_remark = ptime.keep_remark ?? "",
                                 hit_type = ptime.hit_type,
                                 hit_item = t.hit_item ?? "",
                                 maintain_method = t.maintain_method ?? "",
                                 corepairer = record.corepairer
                             }).GroupBy(t => t.ptimeid).Select(t => t.FirstOrDefault()).ToList();

            return queryList;
        }


        #endregion
    }
}
