using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.TpmRepository.Entities;

namespace Siger.Middlelayer.TpmRepository.Repositories
{
    internal abstract class TpmRepositoryBase<TEntity> : RepositoryBase<TEntity> where TEntity : TpmEntityBase
    {
        private readonly ApiTpmDbContext _context;
        protected TpmRepositoryBase(ApiTpmDbContext context) : base(context)
        {
            _context = context;
        }

        public IEnumerable<siger_project_level_section> GetParentLevelSections(int id, int projectid)
        {
            var query = from c in _context.siger_project_level_section
                        where c.id == id && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLevelSections(t.parentid, projectid)));
        }

        public IEnumerable<siger_project_level_section> GetSonLevelSections(int parentId, int projectid)
        {
            var query = from c in _context.siger_project_level_section
                        where c.parentid == parentId && c.projectid == projectid && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonLevelSections(t.id, projectid)));
        }

        public IEnumerable<siger_project_level_section> GetAllSections(int projectid)
        {
            return _context.siger_project_level_section.Where(q => q.projectid == projectid && q.status == (int)RowState.Valid);
        }

        public IEnumerable<siger_project_level_section> GetAllSonLevelSections(int parentId, IEnumerable<siger_project_level_section> list)
        {
            var query = from c in list
                        where c.parentid == parentId && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetAllSonLevelSections(t.id, list)));
        }
        public IEnumerable<siger_project_level_section> GetAllParentLevelSections(int id, IEnumerable<siger_project_level_section> list)
        {
            var query = from c in list
                        where c.id == id && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetAllParentLevelSections(t.parentid, list)));
        }
        public IEnumerable<siger_project_level_section> GetSonLevelSection(int parentId, int projectId)
        {
            var ret = new List<siger_project_level_section>();
            var sections = _context.siger_project_level_section.Where(f => f.projectid == projectId && f.status != 0).AsNoTracking().ToList();
            var self = sections.FirstOrDefault(f => f.id == parentId);
            if (self == null)
            {
                return ret;
            }
            ret = GetAllSonLevelSections(parentId, sections).ToList();
            ret.Add(self);
            return ret.Distinct();
        }
        public List<int> GetMachineIdsBySection(int parentId, int projectId)
        {
            var sectionsIds = GetSonLevelSection(parentId, projectId).Select(s => s.id);
            return _context.siger_project_machine_attribution.Where(f => f.attribution == 1 && f.projectid == projectId && sectionsIds.Contains(f.station) && f.status != 0).AsNoTracking().Select(s => s.machine).Distinct().ToList();
        }

        public IEnumerable<siger_project_level_section> GetParentSelfLevelSections(int parentid, int projectid)
        {
            var query = from c in _context.siger_project_level_section
                        where c.id == parentid && c.status == (int)RowState.Valid
                        select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLevelSections(t.parentid, projectid)));
        }

        public siger_project_level_section GetLevelSectionByMachineId(int machineId, int projectId)
        {
            var levelsectionmachine =
                _context.siger_project_machine_attribution.FirstOrDefault(t =>
                    t.machine == machineId && t.attribution == 1 && t.status == (int)RowState.Valid);
            if (levelsectionmachine != null)
            {
                var levelsection = _context.siger_project_level_section.FirstOrDefault(t =>
                    t.id == levelsectionmachine.station && t.status == (int)RowState.Valid &&
                    t.projectid == projectId);
                if (levelsection != null)
                {
                    return levelsection;
                }
            }
            return null;
        }

        public siger_project_level_section GetTopLevelSection(int projectId)
        {
            return _context.siger_project_level_section.FirstOrDefault(t =>
                t.parentid == 0 && t.status == (int)RowState.Valid && t.projectid == projectId);
        }

        public IEnumerable<siger_project_repair_add_user> GetAddUserListByRepairId(int repairId)
        {
            return _context.siger_project_repair_add_user.Where(t => t.repairid == repairId && t.status == (int)RowState.Valid);
        }

        public IEnumerable<siger_project_machine_fault> GetMachineFaultByFaultId(int faultId, int projectId)
        {
            return _context.siger_project_machine_fault.Where(t => t.id == faultId && t.status == (int)RowState.Valid && t.projectid == projectId);
        }

        public siger_app_mute GetAppMuteByRepairId(int repairId, int projectId, int userId)
        {
            return _context.siger_app_mute.FirstOrDefault(t => t.repairid == repairId && t.projectid == projectId && t.mid == userId);
        }

        public siger_project_section GetSectionByUserId(int userId)
        {
            var query = from p in _context.siger_project_user
                        join q in _context.siger_project_section
                        on p.sectionid equals q.id
                        where p.status == (int)RowState.Valid && p.mid == userId && q.status == (int)RowState.Valid
                        select q;

            return query.FirstOrDefault();
        }

        public IEnumerable<siger_project_user> GetUserBySectionType(int projectId, int type)
        {
            if (type == 0)
            {
                var query = from user in _context.siger_project_user
                            join section in _context.siger_project_section
                            on user.sectionid equals section.id
                            where user.status == (int)RowState.Valid && section.status == (int)RowState.Valid
                            && user.projectid == projectId
                            select user;
                return query;
            }
            else
            {
                var query = from user in _context.siger_project_user
                            join section in _context.siger_project_section
                            on user.sectionid equals section.id
                            where user.status == (int)RowState.Valid && section.status == (int)RowState.Valid
                            && user.projectid == projectId && section.type == type
                            select user;
                return query;
            }
        }

        public IEnumerable<int> ListAllMidArrBySectionIDArr(IEnumerable<int> sectionIds, int time)
        {
            var date = UnixTimeHelper.ConvertIntDateTime(time).ToDateTime();
            int this_time = date.Hour * 3600 + date.Minute * 60 + date.Millisecond;
            var rowstate = (int)RowState.Valid;
            var query = from sta in _context.siger_project_station
                        join pug in _context.siger_project_user_group on sta.groupid equals pug.groupid
                        join sh in _context.siger_project_shift on sta.shiftid equals sh.id
                        where sh.status == rowstate && sectionIds.Contains(sta.sectionid) && pug.mid > 0 && sta.status == rowstate
                        && (sh.start_time < sh.end_time ? (sh.start_time <= this_time && this_time <= sh.end_time) : (sh.start_time <= this_time || this_time <= sh.end_time))
                        && time >= sta.starttime && time <= sta.endtime
                        select pug;
            var mids = new List<int>();
            var dataList = query.ToList();
            if (dataList.Any())
            {
                mids = dataList.Select(t => t.mid).ToList();
            }
            return mids;
        }

        public string GetUserOpenId(int mid, int projectId)
        {
            var entity = _context.siger_app_project_user.FirstOrDefault(q =>
                q.projectId == projectId && q.mid == mid && q.status == (int)RowState.Valid);
            if (entity != null)
            {
                return entity.openid;
            }

            return string.Empty;
        }

        public int GetProjectLanguage(int projectId)
        {
            var project = _context.siger_project.FirstOrDefault(t => t.id == projectId);
            return project?.language ?? 0;
        }

        public siger_project_user GetUserByMid(int mid)
        {
            return _context.siger_project_user.FirstOrDefault(t => t.mid == mid && t.status == (int)RowState.Valid);
        }

        public IEnumerable<int> GetUserIdsByDepartment(int department, int projectId)
        {
            var query = from q in _context.siger_project_user
                        where q.status == (int)RowState.Valid && q.projectid == projectId && q.sectionid == department
                        select new
                        {
                            q.mid
                        };

            return query.Select(t => t.mid).ToList();
        }

        /// <summary>
        /// 获取异常类型子集
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public IEnumerable<siger_andon_expection_type> GetExpectionSonLevel(int parent, int projectid)
        {
            //var query = from c in _context.siger_andon_expection_type
            //            where c.parent == parent && c.projectid == projectid && c.status == (int)RowState.Valid
            //            select c;
            //return query.ToList().Concat(query.ToList().SelectMany(t => GetExpectionSonLevel(t.id, projectid)));

            if (parent == 0)
            {
                return GetAllExpections(projectid);
            }
            var query = (from c in _context.siger_andon_expection_type
                         where c.id == parent && c.projectid == projectid && c.status == (int)RowState.Valid
                         select c).FirstOrDefault();
            if (query != null && query.parent == 0)
            {
                return GetAllExpections(projectid);
            }
            return GetSonLevelExpections(parent, GetAllExpections(projectid));
        }

        private IEnumerable<siger_andon_expection_type> GetSonLevelExpections(int parentId, List<siger_andon_expection_type> sectionList)
        {
            var query = sectionList.Where(f => f.parent == parentId);
            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonLevelExpections(t.id, sectionList)));
        }

        private List<siger_andon_expection_type> GetAllExpections(int projectid)
        {
            return _context.siger_andon_expection_type.Where(q => q.projectid == projectid && q.status == (int)RowState.Valid).AsNoTracking().ToList();
        }


        public List<siger_andon_expection_type> GetExpectionSonSelfLevel(int parent, int projectid)
        {
            var ret = new List<siger_andon_expection_type>();
            var model = _context.siger_andon_expection_type.FirstOrDefault(f => f.projectid == projectid && f.status != 0 && f.id == parent);
            if (model != null)
            {
                ret.Add(model);
            }
            var sons = GetExpectionSonLevel(parent, projectid).ToList();
            if (sons.Any())
            {
                ret.AddRange(sons);
            }
            return ret;
        }

        /// <summary>
        /// 获取异常类型父级
        /// </summary>
        /// <param name="id"></param>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public IEnumerable<siger_andon_expection_type> GetExpectionParent(int id, int projectid)
        {
            var query = from c in _context.siger_andon_expection_type
                        where c.id == id && c.status == (int)RowState.Valid
                        select c;
            return query.ToList().Concat(query.ToList().SelectMany(t => GetExpectionParent(t.parent, projectid)));
        }

        public IEnumerable<siger_andon_expection_type> GetExpectionParent(int id, int projectid, List<siger_andon_expection_type> list)
        {
            var query = from c in list
                        where c.id == id && c.status == (int)RowState.Valid
                        select c;
            return query.ToList().Concat(query.ToList().SelectMany(t => GetExpectionParent(t.parent, projectid, list)));
        }

        public string GetMachineParentName(int machineId, int projectId)
        {
            var machinename = (from q in _context.siger_project_machine_attribution
                               join l in _context.siger_project_level_section on q.station equals l.id
                               join pl in _context.siger_project_level_section on l.parentid equals pl.id
                               where q.machine == machineId && q.projectid == projectId
                               select pl.title + "-" + l.title).FirstOrDefault();

            return machinename ?? "";
        }
    }
}
