using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Request;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.CncRepository.Response;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Common.Helpers;
using Siger.ApiCommon.Result;
using Microsoft.Extensions.Logging;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;
using System.IO;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common.AppSettings;
using Siger.ApiCommon.Filters;
namespace Siger.ApiCNC.Controllers
{
    public class WoTraceController :  BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IProductPlanDetailRepository _planDetailRepository;
        private readonly IProductPlanRepository _planRepository;
        private readonly ISigerWoTraceRepository _WoTraceRepository;
        private readonly ISigerWoTraceDetailsRepository _WoTraceDetailsRepository;
        private readonly ISigerProjectMachineRepository _sigerProjectMachine;
        private readonly ISigerProjectLevelSectionRepository _sigerProjectLevelSection;
        private readonly ISigerProjectLevelSectionMachineRepository _sigerProjectLevelSectionMachine;
        private readonly ISigerProjectUserRepository _sigerProjectUser;
        private readonly ISigerProjectProductReport _sigerProjectProduct;
        private readonly IProduceScheduleRepository _produceSchedule;
        private readonly IProductRouteRepository _productRoute;
        private readonly ISigerBaseSetting _sigerBaseSetting;
        /// <summary>
        /// 南京汽轮机 票据追溯
        /// </summary>
        /// <param name="unitOfWork"></param>
        /// <param name="productPlan"></param>
        /// <param name="productPlanDetail"></param>
        /// <param name="sigerWoTrace"></param>
        /// <param name="sigerWoTraceDetails"></param>
        /// <param name="produceSchedule"></param>
        /// <param name="productRoute"></param>
        /// <param name="sigerProjectMachine"></param>
        /// <param name="sigerProjectLevelSection"></param>
        /// <param name="sigerProjectLevelSectionMachine"></param>
        /// <param name="sigerProjectUser"></param>
        /// <param name="sigerProjectProduct"></param>
        /// <param name="sigerBaseSetting"></param>
        public WoTraceController(IUnitOfWork unitOfWork, IProductPlanRepository productPlan, IProductPlanDetailRepository productPlanDetail, ISigerWoTraceRepository sigerWoTrace, ISigerWoTraceDetailsRepository sigerWoTraceDetails, IProduceScheduleRepository produceSchedule, IProductRouteRepository productRoute,
            ISigerProjectMachineRepository sigerProjectMachine, ISigerProjectLevelSectionRepository sigerProjectLevelSection , ISigerProjectLevelSectionMachineRepository sigerProjectLevelSectionMachine, ISigerProjectUserRepository sigerProjectUser, ISigerProjectProductReport sigerProjectProduct, ISigerBaseSetting sigerBaseSetting)
        {
            _unitOfWork = unitOfWork;
            _planRepository = productPlan;
            _planDetailRepository = productPlanDetail;
            _WoTraceRepository = sigerWoTrace;
            _WoTraceDetailsRepository = sigerWoTraceDetails;
            _sigerProjectMachine = sigerProjectMachine;
            _sigerProjectLevelSection = sigerProjectLevelSection;
            _sigerProjectLevelSectionMachine = sigerProjectLevelSectionMachine;
            _sigerProjectUser = sigerProjectUser;
            _sigerProjectProduct = sigerProjectProduct;
            _produceSchedule = produceSchedule;
            _productRoute = productRoute;
            _sigerBaseSetting = sigerBaseSetting;
        }

        /// <summary>
        /// 查找user ,levelSetion,WoInfo
        /// </summary>
        /// <param name="search"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetScheduleWoInfo([FromBody]RequestWoSearch search)
        {
            var pid = ProjectId;
            var response = new ResponseWoSearch {
            };
            var machine = _sigerProjectMachine.Get(f => f.projectid == pid && f.code == search.Key);
            if (machine!=null)
            {
                var levelsection = _sigerProjectLevelSectionMachine.Get(f => f.machine_id == machine.id);
                if (levelsection==null)
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                response.Section = levelsection.section_id;
                return new ObjectResult(response);
            }
            var user = _sigerProjectUser.Get(f => f.projectid == pid && f.status == (int)RowState.Valid && (f.work_code == search.Key ||  f.rank == search.Key));
            if (user!=null)
            {
                response.User = user.mid;
                return new ObjectResult(response);
            }
            var data = _planDetailRepository.GetWoSchedule(search.Key, pid);
            if (data!=null)
            {
                var reportsData = _sigerProjectProduct.GetList(f => f.projectid == pid && f.plan_id == data.PlanId && f.code == data.OrderNumber);
                if (reportsData.Any())
                {
                    data.Reported = reportsData.Sum(s => s.actual_output) +reportsData.Sum(s=>s.nok_number);
                }
                response.User = data.Uid;
                response.Section = data.SectionId;
                response.Wo = new ScheduleWoInfo ();
                response.Wo = data;
                return new ObjectResult(response);
            }

            throw new BadRequestException(CommonEnum.RecordNotFound);
           
        }
        /// <summary>
        /// 工令单 报工
        /// </summary>
        /// <param name="report"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult Report([FromBody]RequestWoReport report)
        {
            if (report.OkCount==0 && report.NgCount==0 && report.NgCount2==0 )
                throw new BadRequestException(RequestEnum.MaxMinError);
            var pid = ProjectId;
            var user = _sigerProjectUser.Get(f => f.projectid == pid && f.mid == report.Mid);
            if (user == null)
                throw new BadRequestException(ConfigEnum.UserNotFound);

            var plandetials = _planDetailRepository.Get(f => f.projectId == pid && f.orderNumber == report.Wo);
            if (report == null)
                throw new BadRequestException(CommonEnum.RecordNotFound);
            //var repealst = _sigerProjectProduct.GetList(f => f.projectid == pid && f.code == report.Wo);
            //int repeaCount = 0;
            //if (repealst.Any())
            //{
            //    repeaCount += repealst.Select(s => s.actual_output).Sum();
            //    repeaCount += repealst.Select(s => s.nok_number).Sum();
            //}
            // 同一工站下同一个工单 是否做首检
            var Inspection = _WoTraceRepository.Get(f => f.projectId == pid && f.Station== report.SectionId && f.WO == report.Wo && f.Type == (int)WoType.First);
            if (Inspection==null)
            {
                BaseItemChk(report.SectionId);
            }else
            {
                //首检是否通过
                if(Inspection.Result.ToUpper()!="OK")
                {
                    BaseItemChk(report.SectionId);
                }
            }
           
            var plan = _planRepository.Get(f => f.projectid == pid && f.id == plandetials.planId);
            if (plan == null)
                throw new BadRequestException(CommonEnum.RecordNotFound);
            //每道工序都可以报工小于等于订单数量
            if (report.OkCount + report.NgCount + report.NgCount2 > plan.quantity)
            {
                throw new BadRequestException(CncEnum.MaxReportCount);
            }
            if (plan.status == (int)PlanProcess.HasPlan || plan.status == (int)PlanProcess.Producing)
            {
                var route = _productRoute.GetList(f => f.projectId == pid && f.productId == plan.product_id && f.status==(int)RowState.Valid, "serialNumber").FirstOrDefault();
                if (route==null)
                    throw new BadRequestException(CncEnum.RoutesNotFound);
                var schedule = _produceSchedule.Get(f => f.projectId == pid && f.plandetail_id == plandetials.id);
                if (schedule == null)
                    throw new BadRequestException(CncEnum.RouteIsEmpty);

                var curline = _sigerProjectLevelSection.GetlineId(report.SectionId, pid);
                if (plan.status==(int)PlanProcess.HasPlan)
                    plan.status = (int)PlanProcess.Producing;
                var levelmachine = _sigerProjectLevelSectionMachine.Get(f => f.section_id == report.SectionId);
                if (levelmachine==null)
                    throw new BadRequestException(CncEnum.MachineIdNotExist);

                var curroute = _productRoute.Get(f => f.projectId == pid && f.productId == plan.product_id && f.name == schedule.route_name);
                if (curroute==null)
                    throw new BadRequestException(CncEnum.RouteIsEmpty);


                // insert woTrace
                _WoTraceRepository.Insert(new Middlelayer.CncRepository.Entities.siger_project_wo_trace
                {
                    Type= (int)WoType.Report,
                    projectId = pid,
                    SeqID =Guid.NewGuid().ToString(),
                    Line = curline,
                    Station = report.SectionId,
                    Position = report.SectionId,
                    ProductID = plan.product_code,
                    WO=report.Wo,
                    OkCount=report.OkCount,
                    NgCount=report.NgCount,
                    NgCount2=report.NgCount2,
                    DebugCount=report.DebugCount,
                    Result ="OK",
                    TransDateTime=DateTime.Now.ToLocalTime(),
                    LastUpdateTime=DateTime.Now.ToLocalTime(),
                    UID=report.Mid,
                    status = 1
                });
                // insert planReport
                var ret= _sigerProjectProduct.InsertProductReportData(new Middlelayer.Repository.Entities.siger_project_product_report
                {
                    route_name= curroute.id.ToString(),
                   
                    plan_id=plan.id,
                    projectid= pid,
                    machineid= levelmachine.machine_id, 
                    code=report.Wo,
                    //code=plan.ordernumber,
                    uid=report.Mid,
                    worker_code=user.work_code,
                    worker_name=user.name,
                    draw_number=plan.draw_number,
                    product_code=plan.product_code,
                    product_name=plan.product_name,
                    station=report.SectionId,
                    start_time=plandetials.startTime,
                    end_time= plandetials.endTime,
                    time=UnixTimeHelper.GetNow(),
                    //actual_output =report.OkCount,
                    actual_output = report.OkCount +report.DebugCount,
                    nok_number =report.NgCount +report.NgCount2,
                    industrial_waste=report.NgCount,
                    material_waste=report.NgCount2,
                    status=1
                });

                // 插入工令单数量
                //plandetials.ok_number += report.OkCount;
                plandetials.ok_number += report.OkCount + report.DebugCount;
                plandetials.nok_number += report.NgCount + report.NgCount2;
                _planDetailRepository.Update(plandetials);
                // 最后一道工序 
                if (route.name.Equals(schedule.route_name))
                {
                    if (plan.producted_number +plan.nok_number + report.OkCount + report.DebugCount + report.NgCount + report.NgCount2 >= plan.quantity)
                    {
                        plan.status = (int)PlanProcess.Finished;
                    }
                    // 更新工单数量
                    plan.producted_number += report.OkCount+ report.DebugCount;
                    plan.nok_number += report.NgCount + report.NgCount2;
                }else
                {
                    plan.status = (int)PlanProcess.Producing;

                }
                _planRepository.Update(plan);
                if (_unitOfWork.Commit() > 0)
                    return new ObjectResult(CommonEnum.Succefull);
                else
                    throw new BadRequestException(CommonEnum.Fail);

            }
            throw new BadRequestException(CncEnum.PlanNotFound);

        }

        /// <summary>
        /// 检查站别功能
        /// </summary>
        /// <param name="station"></param>
        void BaseItemChk(int station)
        {
            var IsCancel = _sigerBaseSetting.IsExist(f => f.Station == station && f.Seq== (int)BaseSetting.Cancel_InspectionFirst && f.status == (int)RowState.Valid);
            if (!IsCancel)
            {
                throw new BadRequestException(CncEnum.InspectionFirst);
            }
            //if (settingItem.Any())
            //{
            //    if (settingItem.e)
            //    foreach(var item in settingItem)
            //    {
            //        //bit 20 取消报工前首检
            //        if (item.Seq==(int)BaseSetting.BeInspectionFirst)
            //        {
            //            throw new BadRequestException(BaseSetting.BeInspectionFirst);
            //        }
            //    }
            //}
        }
        /// <summary>
        ///  检验
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult WoCheck([FromBody]RequestInspection inspection)
        {
            if (!inspection.Items.Any())
                throw new BadRequestException(RequestEnum.ParameterMiss);

            var pid = ProjectId;
            var planDtls = _planDetailRepository.Get(f => f.projectId == pid && f.orderNumber == inspection.Wo);
            if (planDtls==null)
                throw new BadRequestException(CncEnum.PlanNotFound);
            var plan = _planRepository.Get(planDtls.planId);
            if (plan == null)
                throw new BadRequestException(CncEnum.PlanNotFound);


            var curline = _sigerProjectLevelSection.GetlineId(inspection.SectionId, pid);
            var seqId = Guid.NewGuid().ToString();
            //  inspection
            switch(inspection.Type)
            {
                case WoType.First:
                case WoType.Round:
                case WoType.Complate:
                    {
                        string _result = "OK";
                        foreach (var it in inspection.Items)
                        {
                            if (it.Result.ToUpper() != "OK")
                                _result = "NG";

                            _WoTraceDetailsRepository.Insert(new Middlelayer.CncRepository.Entities.siger_project_wo_trace_details
                            {
                                projectId= pid,
                                SeqID = seqId,
                                Item= it.Item,
                                Value=it.Value,
                                Result=it.Result,
                                Remarks=EnumHelper.GetEnumDesc(inspection.Type),
                                TransDateTime=DateTime.Now.ToLocalTime(),
                                LastUpdateTime=DateTime.Now.ToLocalTime(),
                                status=1

                            });
                        }
                        _WoTraceRepository.Insert(new Middlelayer.CncRepository.Entities.siger_project_wo_trace {
                            projectId= pid,
                            SeqID = seqId,
                            Line = curline,
                            Station = inspection.SectionId,
                            Position = inspection.SectionId,
                            Result = _result,
                            ProductID = plan.product_code,
                            WO = inspection.Wo,
                            Type = (int)inspection.Type, //票据类型
                            UID= inspection.Mid,
                            TransDateTime=DateTime.Now.ToLocalTime(),
                            LastUpdateTime=DateTime.Now.ToLocalTime()
                        });
                        break;
                    }
                case WoType.Full:
                    {
                        //全检只有合格/NG 项
                        foreach (var it in inspection.Items)
                        {
                            _WoTraceRepository.Insert(new Middlelayer.CncRepository.Entities.siger_project_wo_trace
                            {
                                projectId= pid,
                                SeqID = seqId,
                                Line=curline,
                                Station = inspection.SectionId,
                                Position=inspection.SectionId,
                                Result = it.Result==null?"OK":"NG",
                                ProductID= plan.product_code,
                                WO=inspection.Wo,
                                OkCount=it.OKCount,
                                NgCount=it.NgCount,
                                NgCount2=it.NgCount2,
                                UID=inspection.Mid,
                                TransDateTime=DateTime.Now.ToLocalTime(),
                                LastUpdateTime=DateTime.Now.ToLocalTime(),
                                Type=(int)WoType.Full,
                                status=1
                            });
                        }
                    }
                    break;
                default:
                    break;
                    
            }
            if (_unitOfWork.Commit() > 0)
                return new ObjectResult(CommonEnum.Succefull);
            else
                throw new BadRequestException(CommonEnum.Fail);
        }


        /// <summary>
        /// 报表
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="line"></param>
        /// <param name="station"></param>
        /// <param name="wo"></param>
        /// <param name="mid"></param>
        /// <param name="beginTime"></param>
        /// <param name="endTime"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetReport(string productId, int line, int station, string wo, int mid, DateTime beginTime, DateTime endTime,int page=PageIndex,int pageSize=PageSize)
        {
            var report = _WoTraceRepository.GetWoTraceReports(ProjectId, productId, line, station, wo, mid, beginTime, endTime,page,pageSize);
            return new PagedObjectResult(report.Data, report.Total, page, pageSize);
        }

        /// <summary>
        /// 获取明细
        /// </summary>
        /// <param name="traceId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetReportDtl(string traceId)
        {
            var data = _WoTraceDetailsRepository.GetList(f => f.SeqID == traceId);
            return new ObjectResult(data);
        }
        /// <summary>
        /// 导出
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="line"></param>
        /// <param name="station"></param>
        /// <param name="wo"></param>
        /// <param name="mid"></param>
        /// <param name="beginTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportTraceReport(string productId, int line, int station, string wo, int mid, DateTime beginTime, DateTime endTime)
        {

            var trace = _WoTraceRepository.GetWoTraceReports(ProjectId, productId, line, station, wo, mid, beginTime, endTime, 1, 999999);
            var report = _WoTraceRepository.ExportWoTraceReports(ProjectId, productId, line, station, wo, mid, beginTime, endTime);
            if (report == null && !report.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var ExcelSource = new List<WoTraceTemplate>();
            foreach (var r in trace.Data)
            {
                var total = r.OkCount + r.NgCount + r.NgCount2;
                ExcelSource.Add(new WoTraceTemplate
                {
                    Wo = r.Wo, 
                    Product=r.ProductName,
                    DrawCode=r.DrawCode,
                    Line = r.Line,
                    Station = r.Station,
                    Route=r.Route,
                    Operate = r.Operate,
                    Result = r.Result,
                    Total = total,
                    OkCount = r.OkCount,
                    NgCount = r.NgCount,
                    NgCount2 = r.NgCount2,
                    User = r.User,
                    DateTime = r.Time.ToString()
                });
            }

            var ExcelSourceDts = new List<WoTraceDtsTemplate>();
            foreach (var r in report)
            {
                ExcelSourceDts.Add(new WoTraceDtsTemplate
                {
                    Wo = r.Wo,
                    Item = r.Item,
                    Value = r.Value,
                    Result=r.Result
                });
            }

            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            EpPlusExcelHelper<WoTraceTemplate> helper = null;
            try
            {
                helper = new EpPlusExcelHelper<WoTraceTemplate>();
                var temporaryFileName = $"工票统计-{DateTime.Now:yyyyMMddHHmmss}.xlsx";
                helper.GenerateExcel(ExcelSource,ExcelSourceDts, Path.Combine(rootDir, temporaryFileName));
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportTraceReport failed, error:" + e);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper?.Dispose();
            }


        }

    }
}
