using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.Repository.Repositories
{
    internal class SigerProjectMachineTypeRepository: ApiConfigRepositoryBase<siger_project_machine_type>, ISigerProjectMachineTypeRepository
    {
        private readonly ApiConfigDbContext _context;
        public SigerProjectMachineTypeRepository(ApiConfigDbContext context) : base(context)
        {
            _context = context;
        }

        public IEnumerable<LevelSectionTree> GetLevelMachineTypes(int projectid)
        {
            var list = new List<LevelSectionTree>();
            var query = GetSonMachineTypes(0, projectid);

            foreach (var section in query.ToList())
            {
                list.Add(new LevelSectionTree { id = section.id, title=section.title, name = section.title, pid = section.parentid, open = true,disabled=false});
            }

            return list;
        }

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

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

        private int GetMachineCount(int parentId, int projectid)
        {
            var typeIds = GetSonMachineTypes(parentId, projectid).Select(m => m.id).ToList();
            typeIds.Add(parentId);
            return _context.siger_project_machine.Count(q =>
                typeIds.Contains(q.typeid) && q.projectid == projectid && q.status == (int) RowState.Valid);
        }

        public IPagedCollectionResult<MachineType> GetPagedList(int parentType, int childType, string machineName, int projectid, int page, int pagesize)
        {
            var list = new List<MachineType>();
            var query0 = _context.siger_project_machine_type.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid
                                                                                                        && q.parentid == 0);

            var querylist0 = from q in query0
                select new MachineType
                {
                    id = q.id,
                    description = q.description,
                    parentid = q.parentid,
                    t2 = "N/A",
                    t1 = q.title
                };

            var query1 = _context.siger_project_machine_type.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid
                                                                                                        && q.parentid != 0);
            var querylist1 = from q in query1
                join p in _context.siger_project_machine_type on q.parentid equals p.id
                select new MachineType
                {
                    id = q.id,
                    description = q.description,
                    parentid = q.parentid,
                    t2 = q.title,
                    t1 = p.title
                };

            Expression<Func<MachineType, bool>> titleExpression = q => true;
            if (!string.IsNullOrEmpty(machineName))
            {
                titleExpression = q => (q.t1.Contains(machineName) || q.t2.Contains(machineName));
            }
            Expression<Func<MachineType, bool>> childTypeExpression = q => true;
            if (childType != 0)
            {
                childTypeExpression = q => q.id == childType;
            }
            Expression<Func<MachineType, bool>> parentidExpression = q => true;
            if (parentType != 0 && childType == 0) // 取全部子级
            {
                var ids = GetMachineTypeIds(parentType, projectid);
                parentidExpression = q => ids.Contains(q.id);
            }

            var predicate = titleExpression.And(parentidExpression).And(childTypeExpression);

            var querylist = querylist0.Union(querylist1).Where(predicate);

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

            foreach (var machineType in entities)
            {
                list.Add(new MachineType
                {
                    nums = GetMachineCount(machineType.id, projectid),
                    description = machineType.description,
                    id = machineType.id,
                    parentid = machineType.parentid,
                    t1 = machineType.t1,
                    t2 = machineType.t2
                });
            }

            return new PagedCollectionResult<MachineType>(list, totalCount);
        }

        public IList<int> GetMachineTypeIds(int id, int projectid)
        {
            var list = new List<int>();
            var query = GetSonGetMachineTypes(id, projectid);

            foreach (var section in query.ToList())
            {
                list.Add(section.id);
            }

            return list;
        }

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

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

        public CommonImportResult ImportMachineTypes(IEnumerable<MachineTypeList> machineTypes, int projectid)
        {
            var entities = new List<siger_project_machine_type>();
            var machineTypeLists = machineTypes.ToList();
            foreach (var machineType in machineTypeLists)
            {
                var entity = _context.siger_project_machine_type.FirstOrDefault(q => q.title == machineType.ParentType
                                                                                     && q.projectid == projectid
                                                                                     && q.status == (int) RowState.Valid
                                                                                     && q.parentid == 0);
                if (entity != null)
                {
                    if (!string.IsNullOrEmpty(machineType.ChildType))
                    {
                        var childType = _context.siger_project_machine_type.FirstOrDefault(q =>
                            q.title == machineType.ChildType
                            && q.projectid == projectid
                            && q.status == (int) RowState.Valid && q.parentid > 0);
                        if (childType == null)
                        {
                            var machineTypeEntity = new siger_project_machine_type
                            {
                                parentid = entity.id,
                                projectid = projectid,
                                title = machineType.ChildType,
                                description = machineType.Description,
                                status = (int) RowState.Valid
                            };
                            entities.Add(machineTypeEntity);
                        }
                    }
                }
                else
                {
                    var machineTypeEntity = new siger_project_machine_type
                    {
                        parentid = 0,
                        projectid = projectid,
                        title = machineType.ParentType,
                        description = machineType.Description,
                        status = (int) RowState.Valid
                    };
                    _context.siger_project_machine_type.Add(machineTypeEntity);
                    _context.SaveChanges();

                    if (!string.IsNullOrEmpty(machineType.ChildType))
                    {
                        var childType = _context.siger_project_machine_type.FirstOrDefault(q => q.title == machineType.ChildType
                                                                                                && q.projectid == projectid
                                                                                                && q.status == (int)RowState.Valid
                                                                                                && q.parentid > 0);
                        if (childType == null)
                        {
                            var machineTypeChild = new siger_project_machine_type
                            {
                                parentid = machineTypeEntity.id,
                                projectid = projectid,
                                title = machineType.ChildType,
                                description = machineType.Description,
                                status = (int)RowState.Valid
                            };
                            entities.Add(machineTypeChild);
                        }
                    }
                }
            }

            try
            {
                _context.siger_project_machine_type.AddRange(entities);
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        public IEnumerable<MachineType> ExportMachineTypes(int parentType, int childType, string machineName,int projectid)
        {
            var list = new List<MachineType>();
            var query0 = _context.siger_project_machine_type.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid
                                                                                                        && q.parentid == 0);

            var querylist0 = from q in query0
                             select new MachineType
                             {
                                 id = q.id,
                                 description = q.description,
                                 parentid = q.parentid,
                                 t2 = "N/A",
                                 t1 = q.title
                             };

            var query1 = _context.siger_project_machine_type.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid
                                                                                                        && q.parentid != 0);
            var querylist1 = from q in query1
                             join c in _context.siger_project_machine_type on q.parentid equals c.id
                             select new MachineType
                             {
                                 id = q.id,
                                 description = q.description,
                                 parentid = q.parentid,
                                 t2 = c.title,
                                 t1 = q.title
                             };

            Expression<Func<MachineType, bool>> titleExpression = q => true;
            if (!string.IsNullOrEmpty(machineName))
            {
                titleExpression = q => q.t1.Contains(machineName);
            }
            Expression<Func<MachineType, bool>> childTypeExpression = q => true;
            if (childType != 0)
            {
                childTypeExpression = q => q.id == childType;
            }
            Expression<Func<MachineType, bool>> parentidExpression = q => true;
            if (parentType != 0 && childType == 0) // 取全部子级
            {
                var ids = GetMachineTypeIds(parentType, projectid);
                parentidExpression = q => ids.Contains(q.id);
            }

            var predicate = titleExpression.And(parentidExpression).And(childTypeExpression);

            var querylist = querylist0.Union(querylist1).Where(predicate);

            var entities = querylist.Where(predicate).AsNoTracking().ToList();

            foreach (var machineType in entities)
            {
                list.Add(new MachineType
                {
                    nums = GetMachineCount(machineType.id, projectid),
                    description = machineType.description,
                    id = machineType.id,
                    parentid = machineType.parentid,
                    t1 = machineType.t1,
                    t2 = machineType.t2
                });
            }

            return list;
        }

        public IEnumerable<MachineTypes> GetMachineTypes(IEnumerable<int> machineIds, int projectId)
        {
            var query = from m in _context.siger_project_machine
                join t in _context.siger_project_machine_type on m.typeid equals t.id
                where m.projectid == projectId && t.projectid == projectId
                                               && m.status == (int)RowState.Valid && t.status == (int)RowState.Valid
                                               && machineIds.Contains(m.id)
                select new MachineTypes
                {
                    MachineId = m.id,
                    MachineType = t.title
                };

            return query.AsEnumerable();
        }

        public siger_project_machine_type GetMachineType(int typeId)
        {
            return _context.siger_project_machine_type.FirstOrDefault(q =>
                q.id == typeId && q.status == (int)RowState.Valid);
        }
    }
}
