using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using OfficeOpenXml.FormulaParsing.Utilities;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.FieldEnum;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.TlmRepository.Entities;
using Siger.Middlelayer.TlmRepository.Repositories.Interface;
using Siger.Middlelayer.TlmRepository.Request;
using Siger.Middlelayer.TlmRepository.Response;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.TlmRepository.Repositories
{
    internal class ToolLifeToolRepository : TlmRepositoryBase<siger_project_toollife_tool>, IToolLifeToolRepository
    {
        private readonly ApiTlmDbContext _context;
        public ToolLifeToolRepository(ApiTlmDbContext context) : base(context)
        {
            _context = context;
        }

        public bool AddToolInfo(RequestAddToolInfo request, int projectId)
        {
            var entity = new siger_project_toollife_tool
            {
                name = request.name,
                category_name = request.category_name,
                category_id = request.category_id,
                category = (TlmSettingCategory)request.type,
                part_no = request.partno,
                number = request.number,
                image = request.image.ToStr(),
                video = request.video.ToStr(),
                project_id = projectId,
                tool_status = ToolStatus.UnConfirmed,
                grind = request.grind.ToInt(),
                grind_times = request.grind_times.ToInt(),
                grind_type = request.grind_type.ToInt(),
                use_times = request.use_times.ToInt(),
                material_id = request.material_id,
                image_name = request.image_name,
                need_test=request.need_test,
                need_detection = request.need_detection.ToInt()
            };
            _context.siger_project_toollife_tool.Add(entity);
            if (_context.SaveChanges() <= 0)
            {
                return false;
            }

            if(request.paraValue != null && request.paraValue.Any())
            {
                foreach (var keyValue in request.paraValue)
                {
                    if(keyValue == null)
                    {
                        continue;
                    }
                    var parameter = new siger_project_toollife_tool_parameter
                    {
                        parameter_id = keyValue.key.ToInt(),
                        parameter_value = keyValue.value.ToStr(),
                        project_id = projectId,
                        tool_id = entity.id
                    };
                    _context.siger_project_toollife_tool_parameter.Add(parameter);
                }
                _context.SaveChanges();
            }

            return true;
        }

        public IEnumerable<ToolItemInfo> GetToolList(IEnumerable<int> categoryIds, TlmSettingCategory type, int projectid)
        {
            var query = from q in _context.siger_project_toollife_tool
                join m in _context.siger_tr_materials on q.material_id equals m.id
                where q.project_id == projectid && q.status == (int) RowState.Valid
                select new ToolItemInfo
                {
                    id = q.id,
                    name = m.name,
                    category_id = q.category_id,
                    type = q.category,
                    material_id = m.id
                };

            Expression<Func<ToolItemInfo, bool>> categoryExpression = q => true;
            if (categoryIds.Any())
            {
                categoryExpression = q => categoryIds.Contains(q.category_id);
            }
            Expression<Func<ToolItemInfo, bool>> typeExpression = q => true;
            if (type > 0)
            {
                typeExpression = q => q.type == type;
            }

            var expression = categoryExpression.And(typeExpression);

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

        public CommonImportResult ImportToolInfos(IEnumerable<ToolInfoList> infos, int projectid, int userId, TlmSettingCategory categoryType)
        {
            var errors = new List<string>();
            var entities = new List<siger_project_toollife_tool>();
            var rowIndex = 1;
            foreach (var info in infos)
            {
                rowIndex++;

                if (string.IsNullOrWhiteSpace(info.CategoryCode) || string.IsNullOrWhiteSpace(info.ToolCode) || string.IsNullOrWhiteSpace(info.PartNo))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ParameterMiss}");
                }
                var partNoExist = _context.siger_project_toollife_tool.FirstOrDefault(q => q.project_id == projectid && q.part_no == info.PartNo &&
                                                               q.status == (int)RowState.Valid);
                var pnExist = infos.Count(q => q.PartNo == info.PartNo);
                if (partNoExist != null || pnExist > 1)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.PartNoIsExist}");
                }
                var material = _context.siger_tr_materials.FirstOrDefault(t => t.pn == info.PartNo && t.projectId == projectid && t.status == (int)RowState.Valid);
                if(material == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.MaterialNotExist}");
                }
                var numberExist = _context.siger_project_toollife_tool.FirstOrDefault(q => q.project_id == projectid && q.number == info.ToolCode && q.status == (int)RowState.Valid);
                var noExist = infos.Count(t => t.ToolCode == info.ToolCode);
                if (numberExist !=null || noExist>1)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.NumberIsExist}");
                }
                var toolCategory = _context.siger_project_toollife_category.FirstOrDefault(t => t.code == info.CategoryCode && t.project_id == projectid && t.status == (int)RowState.Valid);
                if(toolCategory == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.Cutter_typeNotNull}");
                }
                else
                {
                    var toolCategory1 = _context.siger_project_toollife_category.FirstOrDefault(t => t.parent == toolCategory.id && t.project_id == projectid && t.status == (int)RowState.Valid);
                    if (toolCategory1 != null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.OnlyLastLevelCanBind}");
                    }
                }

                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
                var entity = new siger_project_toollife_tool
                {
                    name = material.name,
                    category_name = toolCategory.name,
                    category_id = toolCategory.id,
                    category = categoryType,
                    part_no = material.pn,
                    number = info.ToolCode,
                    image = "",
                    video = "",
                    project_id = projectid,
                    tool_status = ToolStatus.UnConfirmed,
                    grind = info.IsGrind.ToInt(),
                    grind_times = info.GrindTimes.ToInt(),
                    grind_type = info.GrindType.ToInt(),
                    use_times = info.UseTimes.ToInt(),
                    need_test = info.need_test == "是" ? 1 : info.need_test == "否" ? 2 : 0,
                    need_detection = info.need_detection == "是" ? 1 : info.need_detection == "否" ? 2 : 0,
                    material_id = material.id
                };
                entities.Add(entity);
            }

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

        public IEnumerable<ResponseGetMaterials> GetMaterialListEx(int id, string part_no, string name, int count, int projectid)
        {
            var queryList = from q in _context.siger_tr_materials
                            join c in _context.siger_tr_material_type on q.typeid equals c.id
                            where q.status == (int)RowState.Valid && q.projectId == projectid && c.status == (int)RowState.Valid
                            select new ResponseGetMaterials
                            {
                                id = q.id,
                                category = c.name,
                                name = q.name,
                                part_no = q.pn,
                                supplier = string.Empty
                            };

            Expression<Func<ResponseGetMaterials, bool>> idExpression = q => true;
            if (id > 0)
            {
                idExpression = q => q.id == id;
            }
            Expression<Func<ResponseGetMaterials, bool>> pnExpression = q => true;
            if (!string.IsNullOrWhiteSpace(part_no))
            {
                pnExpression = q => q.part_no.StartsWith(part_no);
            }
            Expression<Func<ResponseGetMaterials, bool>> nameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(name))
            {
                nameExpression = q => q.name.StartsWith(name);
            }
            var expression = idExpression.And(pnExpression).And(nameExpression);

            if (count > 0)
            {
                return queryList.Where(expression).Take(count).ToList();
            }
            return queryList.Where(expression).ToList();
        }

        public IEnumerable<siger_project_toollife_tool> GetToolInfos(IEnumerable<int> categoryIds, string name, TlmSettingCategory type, int projectid)
        {
            var query = from q in _context.siger_project_toollife_tool
                        join m in _context.siger_tr_materials on q.material_id equals m.id
                        join c in _context.siger_project_toollife_category on q.category_id equals c.id
                        where q.project_id == projectid && q.status == (int)RowState.Valid && c.status == (int)RowState.Valid && c.project_id==projectid
                        select new siger_project_toollife_tool
                        {
                            id = q.id,
                            name = m.name,
                            category_id = q.category_id,
                            category = q.category,
                            material_id = m.id,
                            category_name = c.name,
                            grind=q.grind,
                            grind_times=q.grind_times,
                            grind_type=q.grind_type,
                            number=q.number,
                            part_no=q.part_no,
                            use_times=q.use_times
                        };

            Expression<Func<siger_project_toollife_tool, bool>> categoryExpression = q => true;
            if (categoryIds.Any() || !string.IsNullOrEmpty(name))
            {
                categoryExpression = q => (categoryIds.Contains(q.category_id) || q.name.Contains(name));
            }
            Expression<Func<siger_project_toollife_tool, bool>> typeExpression = q => true;
            if (type > 0)
            {
                typeExpression = q => q.category == type;
            }

            var expression = categoryExpression.And(typeExpression);

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