using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.CncRepository.Entities;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Response;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;

namespace Siger.Middlelayer.CncRepository.Repositories
{
    internal class MachineCurrentStateRepository : CncRepositoryBase<siger_project_working_machine_current_state>, IMachineCurrentStateRepository
    {
        private readonly ApiCncDbContext _context;
        public MachineCurrentStateRepository(ApiCncDbContext context) : base(context)
        {
            _context = context;
        }

        public IEnumerable<ResponseMachineBeatAnalysis> GetMachineBeatAnalysis(int levelId, string timerange, int workgroupId, int userId,
            int projectId)
        {
            var queryList = from q in _context.siger_project_working_machine_current_state
                join st in _context.siger_project_working_machine_states on q.machine_state equals st.state_code.ToInt()
                join u in _context.siger_project_user on q.user_mid equals u.mid
                join s in _context.siger_project_section on u.sectionid equals s.id
                join m in _context.siger_project_machine on q.machine_id equals m.id
                join w in _context.siger_project_working_group on q.workgroup_id equals w.id into ww
                from w1 in ww.DefaultIfEmpty()
                join p in _context.siger_project_product on q.product_id equals p.id into pp
                from p1 in pp.DefaultIfEmpty()
                where q.project_id == projectId && st.project_id == projectId && st.status == (int)RowState.Valid
                      && q.status == (int)RowState.Valid && m.status == (int)RowState.Valid
                select new ResponseMachineBeatAnalysis
                {
                    id = q.id,
                    machine_id = q.machine_id,
                    machine_name = m.title,
                    start_time = q.start_time.ToString(ParameterConstant.DateTimeFormat),
                    end_time = q.end_time == DateTime.MinValue ? "NA" : q.end_time.ToString(ParameterConstant.DateTimeFormat),
                    state = q.machine_state,
                    state_name = st.state_name,
                    section_id = s.id,
                    section_name = s.title,
                    user_mid = u.mid,
                    user_name = u.name,
                    product_name = p1 == null ? "" : p1.name,
                    drawcode = p1 == null ? "" : p1.drawingcode,
                    workgroup_id = w1 == null ? 0 : w1.id,
                    workgroup_name = w1 == null ? "" : w1.name,
                    route_name = q.route_name,
                    start = q.start_time,
                    end = q.end_time
                };

            Expression<Func<ResponseMachineBeatAnalysis, bool>> timeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(timerange))
            {
                var times = timerange.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries);
                if (times.Length == 2)
                {
                    var dtStart = times[0].ToDateTime();
                    var dtEnd = times[1].ToDateTime();
                    timeExpression = q => q.start >= dtStart && q.end <= dtEnd;
                }
            }
            Expression<Func<ResponseMachineBeatAnalysis, bool>> levelExpression = q => true;
            if (levelId != 0)
            {
                var sonMachineIds = GetLevelSectionMachineIds(levelId, projectId);
                levelExpression = q => sonMachineIds.Contains(q.machine_id);
            }
            Expression<Func<ResponseMachineBeatAnalysis, bool>> workgroupExpression = q => true;
            if (workgroupId != 0)
            {
                workgroupExpression = q => q.workgroup_id == workgroupId;
            }
            Expression<Func<ResponseMachineBeatAnalysis, bool>> userExpression = q => true;
            if (userId != 0)
            {
                userExpression = q => q.user_mid == userId;
            }
            var predicate = timeExpression.And(levelExpression).And(workgroupExpression).And(userExpression);
            var entities = queryList.Where(predicate).AsNoTracking().ToList();

            return entities;
        }

        public IPagedCollectionResult<ResponseMachineStateRecord> GetPagedCollectionResult(string timerange, int sectionId, int workgroupId, int userId, 
            int projectId, int state = 0, int page = 1, int pagesize = 10, int toexcel = 0)
        {
            var queryList = from q in _context.siger_project_working_machine_current_state
                join st in _context.siger_project_working_machine_states on q.machine_state equals st.state_code.ToInt()
                join u in _context.siger_project_user on q.user_mid equals u.mid
                join s in _context.siger_project_section on u.sectionid equals s.id
                join m in _context.siger_project_machine on q.machine_id equals m.id
                join w in _context.siger_project_working_group on q.workgroup_id equals w.id into ww
                from w1 in ww.DefaultIfEmpty()
                join p in _context.siger_project_product on q.product_id equals p.id into pp
                from p1 in pp.DefaultIfEmpty()
                where q.project_id == projectId && st.project_id == projectId && st.status == (int)RowState.Valid
                      && q.status == (int) RowState.Valid && m.status == (int)RowState.Valid
                select new ResponseMachineStateRecord
                {
                    id = q.id,
                    machine_id = q.machine_id,
                    start_time = q.start_time.ToString(ParameterConstant.DateTimeFormat),
                    end_time = q.end_time == DateTime.MinValue ? "NA" : q.end_time.ToString(ParameterConstant.DateTimeFormat),
                    state = q.machine_state,
                    state_name = st.state_name,
                    section_id = s.id,
                    section_name = s.title,
                    user_mid = u.mid,
                    user_name = u.name,
                    product_name = p1 == null ? "" : p1.name,
                    workgroup_id = w1 == null ? 0 : w1.id,
                    workgroup_name = w1 == null ? "" : w1.name,
                    route_name = q.route_name,
                    start = q.start_time,
                    end = q.end_time
                };

            Expression<Func<ResponseMachineStateRecord, bool>> timeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(timerange))
            {
                var times = timerange.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries);
                if (times.Length == 2)
                {
                    var dtStart = times[0].ToDateTime();
                    var dtEnd = times[1].ToDateTime();
                    timeExpression = q => q.start >= dtStart && q.end <= dtEnd;
                }
            }
            Expression<Func<ResponseMachineStateRecord, bool>> sectionExpression = q => true;
            if (sectionId != 0)
            {
                sectionExpression = q => q.section_id == sectionId;
            }
            Expression<Func<ResponseMachineStateRecord, bool>> workgroupExpression = q => true;
            if (workgroupId != 0)
            {
                workgroupExpression = q => q.workgroup_id == workgroupId;
            }
            Expression<Func<ResponseMachineStateRecord, bool>> userExpression = q => true;
            if (userId != 0)
            {
                userExpression = q => q.user_mid == userId;
            }
            Expression<Func<ResponseMachineStateRecord, bool>> stateExpression = q => true;
            if (state != 0)
            {
                stateExpression = q => q.state == state;
            }

            var predicate = timeExpression.And(sectionExpression).And(workgroupExpression).And(userExpression).And(stateExpression);
            var totalCount = queryList.Count(predicate);
            if (toexcel == 0)
            {
                var entities = queryList.Where(predicate).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
                return new PagedCollectionResult<ResponseMachineStateRecord>(entities, totalCount);
            }
            else
            {
                var entities = queryList.Where(predicate).AsNoTracking().ToList();
                return new PagedCollectionResult<ResponseMachineStateRecord>(entities, totalCount);
            }
        }

        public IEnumerable<siger_project_working_machine_current_state> GetCurrentStates(IEnumerable<int> machineids,
            string timerange, IEnumerable<int> userIds, int state, int projectId)
        {
            var query = _context.siger_project_working_machine_current_state.Where(q =>
                q.project_id == projectId && q.status == (int) RowState.Valid
                                          && machineids.Contains(q.machine_id));
            Expression<Func<siger_project_working_machine_current_state, bool>> timeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(timerange))
            {
                var times = timerange.Split(new string[] { " - " }, StringSplitOptions.RemoveEmptyEntries);
                if (times.Length == 2)
                {
                    var dtStart = times[0].ToDateTime();
                    var dtEnd = times[1].ToDateTime();
                    timeExpression = q => q.start_time >= dtStart && q.end_time <= dtEnd;
                }
            }
            Expression<Func<siger_project_working_machine_current_state, bool>> stateExpression = q => true;
            if (state != 0)
            {
                stateExpression = q => q.machine_state == state;
            }
            Expression<Func<siger_project_working_machine_current_state, bool>> userExpression = q => true;
            if (userIds != null)
            {
                userExpression = q => userIds.Contains(q.user_mid);
            }

            var predicate = timeExpression.And(stateExpression).And(userExpression);

            var minDate = DateTime.MinValue;
            return query.Where(predicate).Select(m => new siger_project_working_machine_current_state
            {
                id = m.id,
                end_time = m.end_time == minDate ? DateTime.Now : m.end_time,
                machine_id = m.machine_id,
                machine_state = m.machine_state,
                order_number = m.order_number,
                project_id = m.project_id,
                product_id = m.product_id,
                route_name = m.route_name,
                start_time = m.start_time,
                status = m.status,
                workgroup_id = m.workgroup_id,
                user_mid = m.user_mid
            }).ToList();
        }
    }
}
