using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.QmsRepository.Entities;
using Siger.Middlelayer.QmsRepository.Repositories.Interface;
using Siger.Middlelayer.QmsRepository.Response;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.QmsRepository.Repositories
{
    internal class InspectStandardMaterialRepository : QMSRepositoryBase<siger_qms_inspection_standard_material>, IInspectStandardMaterialRepository
    {
        private readonly ApiQmsDbContext _context;
        public InspectStandardMaterialRepository(ApiQmsDbContext context) : base(context)
        {
            _context = context;
        }
        public IPagedCollectionResult<RepsonseInspectStandardMaterial> GetPagedList(int materialid, List<int> sectionid, int projectId, int page, int pagesize)
        {
            var rowstate = (int)RowState.Valid;
            var query = _context.siger_qms_inspection_standard_material.Where(q => q.projectid == projectId && q.status == rowstate);
            var querylist = from q in query
                            join cc in _context.siger_qms_inspection_standard_category on q.categoryid equals cc.id into ccc
                            from cc in ccc.DefaultIfEmpty()
                            join se1 in _context.siger_project_level_section on q.sectionid equals se1.id into section1
                            from se1 in section1.DefaultIfEmpty()
                            join p in _context.siger_tr_materials on q.materialid equals p.id into material
                            from p in material.DefaultIfEmpty()
                            join u in _context.siger_user on q.update_mid equals u.id into user
                            from u in user.DefaultIfEmpty()
                            join unhealthy in _context.siger_qms_inspection_unhealthy on q.unhealthy_id equals unhealthy.id into un
                            from unhealthy in un.DefaultIfEmpty()
                            join category in _context.siger_qms_inspection_unhealthy_category on unhealthy.categoryid equals category.id into c
                            from category in c.DefaultIfEmpty()
                            select new RepsonseInspectStandardMaterial
                            {
                                id = q.id,
                                materialid = q.materialid,
                                materialpn = p.pn,
                                materialname = p.name,
                                materialspec = p.spec,
                                sectionid = q.sectionid,
                                section_value = se1.title ?? "",
                                seq = q.seq,
                                item = q.item,
                                standard = q.standard,
                                unit = q.unit,
                                max_value = q.max_value,
                                min_value = q.min_value,
                                unhealthy_code = unhealthy.code ?? "",
                                unhealthy_desc = q.unhealthy_desc,
                                update_mid = u.nickname ?? "",
                                update_time = UnixTimeHelper.ConvertIntDateTime(q.update_time),
                                value_type = q.value_type,
                                unhealthy_id = q.unhealthy_id,
                                unhealthy_name = unhealthy.name ?? "",
                                unhealthy_category_id = unhealthy != null ? unhealthy.categoryid : 0,
                                unhealthy_category_name = category.name ?? "",
                                categoryid = q.categoryid,
                                categoryname = cc.name ?? "",
                                value_category = q.value_category,
                                range = q.range
                            };

            Expression<Func<RepsonseInspectStandardMaterial, bool>> materialExpression = q => true;
            if (materialid > 0)
            {
                materialExpression = q => q.materialid == materialid;
            }
            Expression<Func<RepsonseInspectStandardMaterial, bool>> sectionExpression = q => true;
            if (sectionid.Any())
            {
                sectionExpression = q => sectionid.Contains(q.sectionid);
            }
            var expression = materialExpression.And(sectionExpression);
            var totalCount = querylist.GroupBy(t => t.id).Select(t => t.FirstOrDefault()).Count(expression);
            var entities = querylist.Where(expression).OrderByDescending(t => t.update_time).GroupBy(t => t.id).Select(t => t.FirstOrDefault())
                .Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
            return new PagedCollectionResult<RepsonseInspectStandardMaterial>(entities, totalCount);
        }

        public IEnumerable<RepsonseInspectStandardMaterial> GetDataList(int materialid, List<int> sectionid, int projectId)
        {
            var rowstate = (int)RowState.Valid;
            var query = _context.siger_qms_inspection_standard_material.Where(q => q.projectid == projectId && q.status == rowstate);
            var querylist = from q in query
                            join cc in _context.siger_qms_inspection_standard_category on q.categoryid equals cc.id into ccc
                            from cc in ccc.DefaultIfEmpty()
                            join se1 in _context.siger_project_level_section on q.sectionid equals se1.id into section1
                            from se1 in section1.DefaultIfEmpty()
                            join p in _context.siger_tr_materials on q.materialid equals p.id into material
                            from p in material.DefaultIfEmpty()
                            join u in _context.siger_user on q.update_mid equals u.id into user
                            from u in user.DefaultIfEmpty()
                            join unhealthy in _context.siger_qms_inspection_unhealthy on q.unhealthy_id equals unhealthy.id into un
                            from unhealthy in un.DefaultIfEmpty()
                            join category in _context.siger_qms_inspection_unhealthy_category on unhealthy.categoryid equals category.id into c
                            from category in c.DefaultIfEmpty()
                            select new RepsonseInspectStandardMaterial
                            {
                                id = q.id,
                                materialid = q.materialid,
                                materialpn = p.pn,
                                materialname = p.name,
                                materialspec = p.spec,
                                sectionid = q.sectionid,
                                section_value = se1.title ?? "",
                                seq = q.seq,
                                item = q.item,
                                standard = q.standard,
                                unit = q.unit,
                                max_value = q.max_value,
                                min_value = q.min_value,
                                unhealthy_code = unhealthy.code ?? "",
                                unhealthy_desc = q.unhealthy_desc,
                                update_mid = u.nickname ?? "",
                                update_time = UnixTimeHelper.ConvertIntDateTime(q.update_time),
                                value_type = q.value_type,
                                unhealthy_id = q.unhealthy_id,
                                unhealthy_name = unhealthy.name ?? "",
                                unhealthy_category_id = unhealthy != null ? unhealthy.categoryid : 0,
                                unhealthy_category_name = category.name ?? "",
                                categoryid = q.categoryid,
                                categoryname = cc.name ?? "",
                                value_category = q.value_category,
                                range = q.range
                            };

            Expression<Func<RepsonseInspectStandardMaterial, bool>> materialExpression = q => true;
            if (materialid > 0)
            {
                materialExpression = q => q.materialid == materialid;
            }
            Expression<Func<RepsonseInspectStandardMaterial, bool>> sectionExpression = q => true;
            if (sectionid.Any())
            {
                sectionExpression = q => sectionid.Contains(q.sectionid);
            }
            var expression = materialExpression.And(sectionExpression);
            var entities = querylist.Where(expression).OrderByDescending(t => t.update_time).GroupBy(t => t.id)
                .Select(t => t.FirstOrDefault()).AsNoTracking().ToList();
            return entities;
        }

        public CommonImportResult ImportInspectionStandard(IEnumerable<InspectionStandardMaterialLevelTemplate> standards, int levelCount, int projectid, int userid)
        {
            try
            {
                var errors = new List<string>();
                var rowIndex = 1;         
                var standardList = new List<InspectionStandardMaterials>();
                var materials = _context.siger_tr_materials.Where(t => t.projectId == projectid && t.status == (int)RowState.Valid).ToList();
                var levelSections = _context.siger_project_level_section.Where(t => t.projectid == projectid && t.status == (int)RowState.Valid).ToList();
                foreach (var item in standards)
                {
                    rowIndex++;
                    var model = Mapper<InspectionStandardMaterialLevelTemplate, InspectionStandardMaterials>.Map(item);
                    var material = materials.FirstOrDefault(t => t.pn == item.materialpn);
                    if(material == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.MaterialNotExist}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }
                    if (item.sections == null || !item.sections.Any() || item.sections.Count != levelCount)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.LineError}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }

                    var pids = new List<int> { 0 };
                    var section = new siger_project_level_section();
                    foreach (var sec in item.sections)
                    {
                        var secs = levelSections.Where(t => t.title == sec && pids.Contains(t.parentid)).ToList();
                        if (!secs.Any())
                        {
                            errors.Add($"{rowIndex},{(int)RequestEnum.LineError}");
                            return new CommonImportResult(0, string.Join(";", errors));
                        }
                        else
                        {
                            pids = secs.Select(t => t.id).ToList();
                        }

                        if (sec == item.sections.Last())
                        {
                            section = secs.FirstOrDefault();
                            if(pids.Count != 1)
                            {
                                errors.Add($"{rowIndex},{(int)RequestEnum.LineError}");
                                return new CommonImportResult(0, string.Join(";", errors));
                            }
                        }
                    }
                    if(section == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.PositionError}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }
                    var unhealthy = _context.siger_qms_inspection_unhealthy.FirstOrDefault(t =>
                            t.code == item.unhealthy_code && t.status == (int)RowState.Valid && t.projectid == projectid);
                    if (unhealthy == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.UnhealthyCodeNotFound}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }
                    var category = _context.siger_qms_inspection_standard_category.FirstOrDefault(t => t.projectid == projectid &&
                        t.status == (int)RowState.Valid && t.name == item.category);
                    if(category == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.CategoryNotNull}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }

                    if (string.IsNullOrEmpty(item.item))
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.ParameterMiss}");
                    }

                    model.materialid = material.id;
                    model.sectionid = section.id;
                    model.unhealthyid = unhealthy.id;
                    model.unhealthyname = unhealthy.name;
                    model.categoryid = category.id;

                    if(string.IsNullOrEmpty(item.max_value) && !string.IsNullOrEmpty(item.min_value))
                    {
                        model.max_value = QmsLimitValue.MaxValue;
                    }
                    if (!string.IsNullOrEmpty(item.max_value) && string.IsNullOrEmpty(item.min_value))
                    {
                        model.min_value = QmsLimitValue.MinValue;
                    }

                    standardList.Add(model);
                }
                rowIndex = 1;
                var newList = new List<InspectionStandardMaterials>();
                foreach (var p in standardList)
                {
                    rowIndex++;                                              
                    if (p.value_type != "2")
                    {
                        p.max_value = "";
                        p.min_value = "";
                    }
                    if (p.value_type == "2" && (string.IsNullOrEmpty(p.min_value) || string.IsNullOrEmpty(p.max_value) ||
                        p.min_value.ToDouble() > p.max_value.ToDouble()))
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.MaxMinError}");
                    }

                    if((p.value_category.ToInt() == (int)ValueCategory.Maxmin && string.IsNullOrEmpty(p.range)) || p.seq <= 0 ||
                        (p.value_type.ToInt() == (int)ValueTypeStatus.V && p.value_category.ToInt() <= 0))
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.ParameterMiss}");
                    }

                    //var queryItem = _context.siger_qms_inspection_standard_material.FirstOrDefault(t => t.item == p.item  &&
                    //    t.projectid == projectid && t.status == (int)RowState.Valid && t.materialid == p.materialid && t.sectionid == p.sectionid);
                    //if(queryItem != null || standardList.Count(t => t.item == p.item  && 
                    //    t.materialid == p.materialid && t.sectionid == p.sectionid) > 1)
                    //{
                    //    errors.Add($"{rowIndex},{(int)RequestEnum.InspectItemRepeat}");
                    //}

                    var querySeq = _context.siger_qms_inspection_standard_material.FirstOrDefault(t => t.seq == p.seq &&
                        t.projectid == projectid && t.status == (int)RowState.Valid && t.materialid == p.materialid && t.sectionid == p.sectionid);
                    if (querySeq != null || standardList.Count(t => t.seq == p.seq &&
                         t.materialid == p.materialid && t.sectionid == p.sectionid) > 1)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.ItemSeqExsit}");
                    }

                    //var seqs = newList.Count(t => t.materialid == p.materialid && t.sectionid == p.sectionid);
                    //p.seq = seqs > 0 ? seqs + 1 : 1;
                    newList.Add(p);
                }
                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }

                var entities = new List<siger_qms_inspection_standard_material>();
                foreach (var p in newList)
                {
                    //var seqs = _context.siger_qms_inspection_standard_material.Count(t => t.projectid == projectid
                    //    && t.sectionid == p.sectionid && t.materialid == p.materialid && t.status == (int)RowState.Valid);
                    //seqs = seqs > 0 ? seqs + p.seq : p.seq;

                    var psEntity = new siger_qms_inspection_standard_material
                    {
                        materialid = p.materialid,
                        sectionid = p.sectionid,
                        standard = p.standard,
                        seq = p.seq,//seqs,
                        item = p.item ?? "",
                        unit = p.unit ?? "",
                        max_value = Math.Round(p.max_value.ToDouble(), 4),
                        min_value = Math.Round(p.min_value.ToDouble(), 4),
                        unhealthy_code = p.unhealthy_code,
                        unhealthy_desc = p.unhealthyname,
                        value_type = p.value_type.ToInt(),
                        create_mid = userid,
                        create_time = UnixTimeHelper.GetNow(),
                        update_mid = userid,
                        update_time = UnixTimeHelper.GetNow(),
                        projectid = projectid,
                        status = (int)RowState.Valid,
                        unhealthy_id = p.unhealthyid,
                        categoryid = p.categoryid,
                        value_category = p.value_category.ToInt(),
                        range = p.range.ToDouble()
                    };
                    entities.Add(psEntity);
                }
            
                _context.siger_qms_inspection_standard_material.AddRange(entities);
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch(Exception ex)
            {
                Logger.WriteLineError(ex.ToString());
                throw;
            }
        }

        public RepsonseInspectStandardMaterial GetData(int id, int projectId)
        {
            var rowstate = (int)RowState.Valid;
            var query = _context.siger_qms_inspection_standard_material.Where(q => q.projectid == projectId && q.status == rowstate && q.id == id);
            var querylist = from q in query
                            join cc in _context.siger_qms_inspection_standard_category on q.categoryid equals cc.id into ccc
                            from cc in ccc.DefaultIfEmpty()
                            join se1 in _context.siger_project_level_section on q.sectionid equals se1.id into section1
                            from se1 in section1.DefaultIfEmpty()
                            join p in _context.siger_tr_materials on q.materialid equals p.id into material
                            from p in material.DefaultIfEmpty()
                            join u in _context.siger_user on q.update_mid equals u.id into user
                            from u in user.DefaultIfEmpty()
                            join unhealthy in _context.siger_qms_inspection_unhealthy on q.unhealthy_id equals unhealthy.id into un
                            from unhealthy in un.DefaultIfEmpty()
                            join category in _context.siger_qms_inspection_unhealthy_category on unhealthy.categoryid equals category.id into c
                            from category in c.DefaultIfEmpty()
                            orderby q.update_time descending
                            select new RepsonseInspectStandardMaterial
                            {
                                id = q.id,
                                materialid = q.materialid,
                                materialpn = p.pn,
                                materialname = p.name,
                                materialspec = p.spec,
                                sectionid = q.sectionid,
                                section_value = se1.title ?? "",
                                seq = q.seq,
                                item = q.item,
                                standard = q.standard,
                                unit = q.unit,
                                max_value = q.max_value,
                                min_value = q.min_value,
                                unhealthy_code = unhealthy.code,
                                unhealthy_desc = unhealthy.name,
                                update_mid = u.nickname ?? "",
                                update_time = UnixTimeHelper.ConvertIntDateTime(q.update_time),
                                value_type = q.value_type,
                                unhealthy_id = q.unhealthy_id,
                                unhealthy_name = unhealthy.name ?? "",
                                unhealthy_category_id = unhealthy != null ? unhealthy.categoryid : 0,
                                unhealthy_category_name = category.name ?? "",
                                categoryid = q.categoryid,
                                categoryname = cc.name ?? "",
                                value_category = q.value_category,
                                range = q.range
                            };
            return querylist.FirstOrDefault();
        }
    }
}
