using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
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.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.Utility.ExcelImport;
using Siger.Middlelayer.Utility.ImportEntities;

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

        public IPagedCollectionResult<ResponseBeatSet> GetPagedList(int sectionid, string product_name_text, string drawing_number, int projectId, int page,
            int pagesize)
        {
            var queryList = from q in _context.siger_project_beat_set
                where q.projectID == projectId && q.status == (int) RowState.Valid orderby q.add_time descending
                select new ResponseBeatSet
                {
                    id = q.id,
                    add_time = q.add_time.ToString(ParameterConstant.DateTimeFormat),
                    createtime = q.add_time,
                    machineID = q.machineID,
                    section_id = q.section_id,
                    process_number = q.process_number,
                    product_name = q.product_name,
                    product_name_text = q.product_name_text,
                    drawing_number = q.drawing_number,
                    standard_besat = q.standard_besat,
                    daily_standard_output = q.daily_standard_output,
                    time_num = q.changemodeltime,
                    routeName = q.route_name,
                    route_number = q.route_number,
                    updown_besat = q.updown_besat,
                    yieldrate = q.yieldrate,
                    start_time = q.start_time.ToString(ParameterConstant.DateFormat),
                    end_time = q.end_time.ToString(ParameterConstant.DateFormat)
                };
            Expression<Func<ResponseBeatSet, bool>> sectionExpression = q => true;
            if (sectionid != 0)
            {
                var sectionIds = GetLevelSectionIds(sectionid, projectId);
                sectionExpression = q => sectionIds.Contains(q.section_id);
            }
            Expression<Func<ResponseBeatSet, bool>> nameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name_text))
            {
                nameExpression = q => q.product_name_text.Contains(product_name_text);
            }
            Expression<Func<ResponseBeatSet, bool>> numberExpression = q => true;
            if (!string.IsNullOrEmpty(drawing_number))
            {
                numberExpression = q => q.drawing_number.Contains(drawing_number);
            }
            var predicate = sectionExpression.And(nameExpression).And(numberExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderByDescending(q => q.createtime).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ResponseBeatSet>(entities, totalCount);
        }

        public IEnumerable<ResponseGetBeatInfo> GetBeatInfos(int productId, IEnumerable<int> sectionIds, int projectId)
        {
            var query = from q in _context.siger_project_beat_set
                join p in _context.siger_project_product on q.drawing_number equals p.drawingcode
                where sectionIds.Contains(q.section_id) && p.id == productId && q.status == (int) RowState.Valid
                      && p.status == (int) RowState.Valid && q.projectID == projectId && q.start_time <= DateTime.Now && q.end_time >= DateTime.Now
                select new ResponseGetBeatInfo
                {
                    cycleTime = q.standard_besat,
                    machineId = q.machineID,
                    productId = productId,
                    sectionId = q.section_id
                };

            return query.AsEnumerable();
        }

        public CommonImportResult ImportBeats(IEnumerable<BeatSetEntity> beatSetEntities, int projectid)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var sectionIds = new List<int>();
            var productIds = new List<string>();
            var machineIds = new List<int>();
            foreach (var beatSetEntity in beatSetEntities)
            {
                var sectionId = 0;
                rowIndex++;
                //check levels
                var title = beatSetEntity.Levels.Last();
                var levels = _context.siger_project_level_section.Where(q =>
                    q.title == title && q.projectid == projectid && q.status == (int)RowState.Valid);

                foreach (var level in levels)
                {
                    var sectionTitles = GetLevelSectionTitles(level.id, projectid);
                    if (sectionTitles.All(beatSetEntity.Levels.Contains) && sectionTitles.Count() == beatSetEntity.Levels.Count)
                    {
                        sectionId = level.id;
                        break;
                    }
                }
                if (sectionId == 0)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.LevelNotFound}");
                }
                else
                {
                    sectionIds.Add(sectionId);
                    var machine = (from q in _context.siger_project_machine_attribution
                                   join m in _context.siger_project_machine on q.machine equals m.id
                                   where m.status == (int)RowState.Valid && q.station == sectionId &&
                                         m.projectid == projectid
                                         && q.status == (int)RowState.Valid
                                   select q).FirstOrDefault();
                    if (machine != null)
                    {
                        machineIds.Add(machine.machine);
                        var entity = _context.siger_project_beat_set.FirstOrDefault(q =>
                            q.status == (int)RowState.Valid && q.process_number == beatSetEntity.ProgramNo
                                                             && q.machineID == machine.machine && q.projectID == projectid);
                        if (entity != null)
                        {
                            errors.Add($"{rowIndex},{800306}");
                        }
                    }
                    else
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.MachineNotFound}");
                    }
                }

                var product = _context.siger_project_product.FirstOrDefault(q =>
                    q.drawingcode == beatSetEntity.ProductDrawingCode && q.projectid == projectid
                                                                      && q.status == (int)RowState.Valid);
                if (product == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ProductNotFound}");
                }
                else
                {
                    productIds.Add(product.id.ToString());
                }
                if (!Match(beatSetEntity.ChangeModelTime))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ChangeModelTimeNotInteger}");
                }
                if (!Match(beatSetEntity.CycleTime))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.CycleTimeNotInteger}");
                }
                if (!Match(beatSetEntity.OutPut))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.OutPutNotInteger}");
                }
                if (!Match(beatSetEntity.YieldRate))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.YieldRateNotInteger}");
                }
                if (!Match(beatSetEntity.UpDownBesat))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.UpDownBesatNotInteger}");
                }
                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
            }
            var index = 0;
            var maxTime = "2199-01-01 00:00:00".ToDateTime();
            foreach (var entity in beatSetEntities)
            {
                var beat = new siger_project_beat_set
                {
                    projectID = projectid,
                    status = (int)RowState.Valid,
                    add_time = DateTime.Now,
                    daily_standard_output = entity.OutPut.ToInt(),
                    drawing_number = entity.ProductDrawingCode,
                    process_number = entity.ProgramNo,
                    product_name_text = entity.ProductName,
                    product_name = productIds[index],
                    section_id = sectionIds[index],
                    standard_besat = entity.CycleTime.ToInt(),
                    route_name = entity.RouteName,
                    machineID = machineIds.Count>index?machineIds[index]:0,
                    changemodeltime = entity.ChangeModelTime.ToInt(),
                    updown_besat = entity.UpDownBesat.ToDouble(),
                    yieldrate = entity.YieldRate.ToInt(),
                    route_number = entity.RouteNumber,
                    start_time = string.IsNullOrEmpty(entity.StartTime) ? DateTime.MinValue : entity.StartTime.ToDateTime(),
                    end_time = string.IsNullOrEmpty(entity.EndTime) ? maxTime : entity.EndTime.ToDateTime().AddDays(1).AddSeconds(-1)
                };
                _context.siger_project_beat_set.Add(beat);
                _context.SaveChanges();
                index++;
            }

            return new CommonImportResult(1, "1");
        }
        /// <summary>
        /// 验证正整数
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        private bool Match(string sender)
        {
            //匹配的正则表达式
            Regex r = new Regex(@"^[+]{0,1}(\d+)$");

            //开始匹配
            Match m = r.Match(sender);

            if (m.Success)
            {
                return true;
            }
            else
            {
                return false;
            }
           
        }
        public IEnumerable<ProductReport> GetProductReport(long startTime, long endTime, IEnumerable<int> machineIds, int projectId)
        {
            var query = from q in _context.siger_project_product_report
                        where q.projectid == projectId && q.start_time >= startTime && q.end_time <= endTime &&
                              machineIds.Contains(q.machineid)
                              && q.status == (int)RowState.Valid
                        select new ProductReport
                        {
                            ActualOutput = q.actual_output,
                            ProductDrawCode = q.draw_number,
                            MachineId = q.machineid,
                            StartTime = q.start_time,
                            EndTime = q.end_time,
                            NokNumber = q.nok_number,       
                            UserId = q.uid,
                            OrderNumber = q.code,
                            ProductName = q.product_name,
                            ReportTime = UnixTimeHelper.ConvertIntDateTime(q.time),
                            PlanId = q.plan_id,
                            WorkCode = q.worker_code,
                            Time = q.time
                        };
            //根据设备和产品获取标准节拍
            var reports = new List<ProductReport>();
            foreach (var report in query.ToList())
            {
                var set = _context.siger_project_beat_set.FirstOrDefault(m =>
                    m.machineID == report.MachineId && m.drawing_number == report.ProductDrawCode
                                                    && m.status == (int)RowState.Valid && m.projectID == projectId);
                if (set != null)
                {
                    reports.Add(new ProductReport
                    {
                        ActualOutput = report.ActualOutput,
                        CycleTime = set.standard_besat,
                        UpdownBesat = set.updown_besat,
                        ProductDrawCode = report.ProductDrawCode,
                        MachineId = report.MachineId,
                        StartTime = report.StartTime,
                        EndTime = report.EndTime,
                        NokNumber = report.NokNumber,
                        OrderNumber = report.OrderNumber,
                        ProductName = report.ProductName,
                        ReportTime = report.ReportTime,
                        UserId = report.UserId,
                        PlanId = report.PlanId,
                        WorkCode = report.WorkCode,
                        Time = report.Time
                    });
                }
            }

            return reports;
        }

        public IEnumerable<ProductReport> GetSignProductReport(long startTime, long endTime, IEnumerable<int> machineIds, int projectId)
        {
            var query = from q in _context.siger_project_product_report
                        where q.projectid == projectId && q.time >= startTime && q.time <= endTime &&
                              machineIds.Contains(q.machineid)
                              && q.status == (int)RowState.Valid
                        select new ProductReport
                        {
                            ActualOutput = q.actual_output,
                            ProductDrawCode = q.draw_number,
                            MachineId = q.machineid,
                            StartTime = q.start_time,
                            EndTime = q.end_time,
                            NokNumber = q.nok_number,
                            UserId = q.uid,
                            OrderNumber = q.code,
                            ProductName = q.product_name,
                            ReportTime = UnixTimeHelper.ConvertIntDateTime(q.time),
                            PlanId = q.plan_id,
                            WorkCode = q.worker_code,
                            Time = q.time
                        };
            //根据设备和产品获取标准节拍
            var reports = new List<ProductReport>();
            foreach (var report in query.ToList())
            {
                var set = _context.siger_project_beat_set.FirstOrDefault(m =>
                    m.machineID == report.MachineId && m.drawing_number == report.ProductDrawCode
                                                    && m.status == (int)RowState.Valid && m.projectID == projectId);
                if (set != null)
                {
                    reports.Add(new ProductReport
                    {
                        ActualOutput = report.ActualOutput,
                        CycleTime = set.standard_besat,
                        UpdownBesat = set.updown_besat,
                        ProductDrawCode = report.ProductDrawCode,
                        MachineId = report.MachineId,
                        StartTime = report.StartTime,
                        EndTime = report.EndTime,
                        NokNumber = report.NokNumber,
                        OrderNumber = report.OrderNumber,
                        ProductName = report.ProductName,
                        ReportTime = report.ReportTime,
                        UserId = report.UserId,
                        PlanId = report.PlanId,
                        WorkCode = report.WorkCode,
                        Time = report.Time
                    });
                }
            }

            return reports;
        }
    }
}
