using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Redis.RedisEntities;
using Siger.Middlelayer.Redis.Repositories;
using Siger.Middlelayer.ToolRepository.Entities;
using Siger.Middlelayer.ToolRepository.Repositories.Interface;
using Siger.Middlelayer.ToolRepository.Request;
using Siger.Middlelayer.ToolRepository.Response;

namespace Siger.Middlelayer.ToolRepository.Repositories
{
    internal class SigerProjectToolMSRepository : ApiToolRepositoryBase<SigerProjectToolMS>, ISigerProjectToolMSRepository
    {
        ApiToolDbContext dbContext;
        public SigerProjectToolMSRepository(ApiToolDbContext context) : base(context)
        {
            dbContext = context;
        }

        public IEnumerable<ResponseGetMSStudyList> GetMSStudyList(int sectionID, string programNo, int projectId, out int totalCount, int page, int pageSize)
        {
            var mids = GetMachineIds(sectionID, projectId);

            Expression<Func<ResponseGetMSStudyList, bool>> Funcat = f => true;
            var query = from m in dbContext.siger_project_machine
                        join sp in dbContext.siger_project_tool_spindle_true on m.id equals sp.equipid
                        join tl in dbContext.siger_project_tool_cutter_location_true on sp.id equals tl.spindleid
                        join ms in dbContext.siger_project_tool_ms on m.id equals ms.machine_id
                        join u in dbContext.siger_project_user on ms.userid equals u.mid
                        where m.projectid == projectId && m.status == (int)RowState.Valid && sp.status == (int)RowState.Valid && tl.status == (int)RowState.Valid
                        && mids.Contains(m.id) && tl.is_processing_program != (int)ProcessProgram.NoConfig
                        && ms.project_id==m.projectid && ms.machine_id==m.id && ms.spindle_name == sp.name && ms.cutter_location_name==tl.name && ms.program_no == (tl.is_processing_program == (int)ProcessProgram.MainProgram ? tl.programno : tl.subprogramno)
                        select new ResponseGetMSStudyList
                        {

                            machineID = m.id,
                            machineCode = m.code,
                            machineName = m.title,
                            spindleID=sp.id,
                            spindleName = sp.name,
                            time = ms.update_time,
                            isSub= tl.is_processing_program == (int)ProcessProgram.ChildProgram?1:0,
                            tn =ms.cutter_location_name,
                            type=ms.type,
                            percent=ms.percent,
                            value=ms.threshold,
                            userID=ms.userid,
                            userName=u.name,
                            pn=ms.program_no

                        };

            if (!string.IsNullOrEmpty(programNo))
            {
                Funcat = f => f.pn.Contains(programNo);
            }
            var groupData = query.Where(Funcat)
                .GroupBy(x => new { x.machineID, x.machineName, x.machineCode, x.spindleID, x.spindleName, x.tn, x.pn, x.isSub, x.type, x.percent, x.value, x.userID, x.userName, x.time })
                .Select(g => new ResponseGetMSStudyList
                {
                    machineID = g.Key.machineID,
                    machineName = g.Key.machineName,
                    machineCode = g.Key.machineCode,
                    spindleID = g.Key.spindleID,
                    spindleName = g.Key.spindleName,
                    tn = g.Key.tn,
                    pn = g.Key.pn,
                    isSub = g.Key.isSub,
                    type = g.Key.type,
                    percent = g.Key.percent,
                    value = g.Key.value,
                    userID = g.Key.userID,
                    userName = g.Key.userName,
                    time = g.Key.time

                }).ToList();

            totalCount = groupData.Count();

            return groupData.OrderBy(o => o.machineID).ThenBy(o => o.spindleName).ThenBy(o=>o.tn).ThenBy(o=>o.tn).Skip((page - 1) * pageSize).Take(pageSize).ToList();
            //var mids = GetMachineIds(sectionID, projectId);

            //// var data = GetList(f => f.status == (int)RowState.Valid && f.project_id == projectId && mids.Contains(f.machine_id));
            //Expression<Func<ResponseGetMSStudyList, bool>> Funkey = f => true;
            //var result = from config in dbContext.siger_project_tool_ms
            //             join machineInfo in dbContext.siger_project_machine on config.machine_id equals machineInfo.id 
            //             join spindle in dbContext.siger_project_tool_spindle_true on config.machine_id equals spindle.equipid
            //             where config.spindle_name==spindle.name
            //             join userInfo in dbContext.siger_project_user on config.userid equals userInfo.mid into resultData
            //             from r in resultData.DefaultIfEmpty()
            //             where config.status==(int)RowState.Valid && config.project_id==projectId &&
            //             mids.Contains(config.machine_id)
            //             select new ResponseGetMSStudyList
            //             {
            //                 machineID = machineInfo.id,
            //                 machineName = machineInfo.title,
            //                 machineCode = machineInfo.code,
            //                 spindleName = config.spindle_name,
            //                 spindleID= spindle.id,
            //                 pn = config.program_no,
            //                 tn = config.cutter_location_name,
            //                 type = config.type,
            //                 value = config.threshold,
            //                 percent = config.percent,
            //                 time = config.update_time,
            //                 userID = config.userid,
            //                 userName = r.name
            //             };
            //if (!string.IsNullOrEmpty(programNo))
            //{
            //    Funkey = f => f.pn.Contains(programNo);
            //}
            //totalCount = result.Where(Funkey).Count();
            //result = result.Where(Funkey).Skip((page - 1) * pageSize).Take(pageSize);
            //return result;
        }

        public IEnumerable<ResponseGetMSUnStudyList> GetMSUnStudyList(int sectionID, string programNo,int projectId, out int totalCount, int page, int pageSize)
        {

            var mids = GetMachineIds(sectionID, projectId);
            var mscfg = dbContext.siger_project_tool_ms.Where(f =>mids.Contains(f.machine_id)).ToList();
            Expression<Func<ResponseGetMSUnStudyList, bool>> Funcat = f => true;
            var query = from m in dbContext.siger_project_machine
                        join sp in dbContext.siger_project_tool_spindle_true on m.id equals sp.equipid
                        join tl in dbContext.siger_project_tool_cutter_location_true on sp.id equals tl.spindleid
                        where m.projectid == projectId && m.status == (int)RowState.Valid && sp.status == (int)RowState.Valid && tl.status == (int)RowState.Valid
                        && mids.Contains(m.id) && tl.is_processing_program != (int)ProcessProgram.NoConfig
                        && !mscfg.Exists(f=>f.project_id==m.projectid && f.machine_id==m.id && f.spindle_name==sp.name && f.cutter_location_name==tl.name && f.program_no== (tl.is_processing_program == (int)ProcessProgram.MainProgram ? tl.programno : tl.subprogramno))
                        select new ResponseGetMSUnStudyList
                        {

                            machineID = m.id,
                            machineCode = m.code,
                            machineName = m.title,
                            spindleID = sp.id,
                            spindleName = sp.name,

                            isSub = tl.is_processing_program == (int)ProcessProgram.ChildProgram ? 1 : 0,
                            tn = tl.name,
                            pn = tl.is_processing_program == (int)ProcessProgram.MainProgram ? tl.programno : tl.subprogramno
                            
                        };

            if (!string.IsNullOrEmpty(programNo))
            {
                Funcat = f => f.pn.Contains(programNo);
            }
            var groupData = query.Where(Funcat)
                .GroupBy(x => new { x.machineID, x.machineName, x.machineCode, x.spindleID, x.spindleName, x.tn, x.pn, x.isSub, })
                .Select(g => new ResponseGetMSUnStudyList
                {
                    machineID = g.Key.machineID,
                    machineName = g.Key.machineName,
                    machineCode = g.Key.machineCode,
                    spindleID = g.Key.spindleID,
                    spindleName = g.Key.spindleName,
                    tn = g.Key.tn,
                    pn = g.Key.pn,
                    isSub = g.Key.isSub

                }).ToList();

            totalCount = groupData.Count();

            return groupData.OrderBy(o => o.machineID).ThenBy(o => o.spindleName).ThenBy(o => o.tn).Skip((page - 1) * pageSize).Take(pageSize).ToList();

            //var mids = GetMachineIds(sectionID, projectId);
            //Expression<Func<ResponseGetMSUnStudyList, bool>> Funkey = f => true;
            //Expression<Func<ResponseGetMSUnStudyList, bool>> FunNotNull = f => !string.IsNullOrEmpty(f.pn);
            //var result = from configInfo in dbContext.siger_project_tool_cutter_location_true
            //             join spindleInfo in dbContext.siger_project_tool_spindle_true on configInfo.spindleid equals spindleInfo.id
            //             join machineInfo in dbContext.siger_project_machine on spindleInfo.equipid equals machineInfo.id 
            //             where machineInfo.projectid == projectId && machineInfo.status == (int)RowState.Valid
            //             && spindleInfo.status==(int)RowState.Valid && configInfo.status==(int)RowState.Valid
            //             && mids.Contains(machineInfo.id)
            //             select new ResponseGetMSUnStudyList
            //             {
            //                 machineID = machineInfo.id,
            //                 machineName = machineInfo.title,
            //                 machineCode = machineInfo.code,
            //                 spindleName = spindleInfo.name,
            //                 spindleID = spindleInfo.id,
            //                 isSub = configInfo.is_processing_program == (int)ProcessProgram.ChildProgram ? 1 : 0,
            //                 pn = configInfo.is_processing_program == (int)ProcessProgram.ChildProgram ? configInfo.subprogramno : configInfo.programno,
            //                 tn = configInfo.name,
            //             };
            //if (!string.IsNullOrEmpty(programNo))
            //{
            //    Funkey = f => f.pn.Contains(programNo);
            //}
            //var predicate = Funkey.And(FunNotNull);

            //totalCount = result.Where(predicate).Count();
            //result = result.Where(predicate).Skip((page - 1) * pageSize).Take(pageSize);
            //return result;
        }

        public void MSConfig(int cid, int mid, int spindleID, string spindle, string pn, string tn, List<ConfigValue> values, int companyId, int projectId, int userId, bool isSubProgram)
        {
            var node = new List<ToolMSNode>();
            foreach (var item in values)
            {
                var entity = Get(f => f.status == (int)RowState.Valid && f.project_id == projectId && f.machine_id == mid && f.spindle_name == spindle &&
                f.cutter_location_name == tn && f.program_no == pn&& f.type == (int)item.type);
                if (entity != null)
                {
                    entity.type = (int)item.type;
                    entity.update_time = DateTime.Now;
                    entity.userid = userId;
                    entity.threshold = item.value;
                    entity.percent = item.percent;
                    Update(entity);
                }
                else
                {
                    Insert(new SigerProjectToolMS
                    {
                        company_id = companyId,
                        machine_id = mid,
                        spindle_name = spindle,
                        cutter_location_name = tn,
                        program_no = pn,
                        update_time = DateTime.Now,
                        create_time = DateTime.Now,
                        userid = userId,
                        type = (int)item.type,
                        threshold = item.value,
                        percent = item.percent,
                        project_id = projectId,
                        status = (int)RowState.Valid,
                    });
                }
                node.Add(new ToolMSNode
                {
                    threshold = item.value,
                    percent = item.percent,
                    type = (int)item.type
                }
                );
                SigerProjectToolCutterLocationTrue tnTrue;
                if (isSubProgram)
                {
                    tnTrue = dbContext.siger_project_tool_cutter_location_true.FirstOrDefault(f => f.status == (int)RowState.Valid &&
                    f.spindleid == spindleID && f.subprogramno == pn && f.name == tn && f.is_processing_program == (int)ProcessProgram.ChildProgram);
                }
                else
                {
                    tnTrue = dbContext.siger_project_tool_cutter_location_true.FirstOrDefault(f => f.status == (int)RowState.Valid &&
                    f.spindleid == spindleID && f.programno == pn && f.name == tn && f.is_processing_program == (int)ProcessProgram.MainProgram);
                }
                if (tnTrue == null)
                {
                    throw new BadRequestException(RequestEnum.ToolNotFound);
                }
                tnTrue.msStudied = 1;
                tnTrue.update_time = UnixTimeHelper.GetNow();
                dbContext.siger_project_tool_cutter_location_true.Update(tnTrue);

            }
            if (dbContext.SaveChanges() < 0)
                throw new BadRequestException(CommonEnum.Fail);
            var redisMS = new ToolMSRepository(cid, projectId);
            redisMS.Add(new ToolMS
            {
                mid = mid,
                spindle = spindle,
                tool = tn,
                pn = pn,
                node = node
            });
        }
    }
}
