using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.CncRepository.Entities;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Request;
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;
using Siger.Middlelayer.Repository.Repositories.Interface;

namespace Siger.ApiCNC.Controllers
{
    /// <summary>
    /// 生产派工
    /// </summary>
    public class ProductJobController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IProductPlanRepository _planRepository;
        private readonly IProductPlanDetailRepository _planDetailRepository;
        private readonly IProductRouteRepository _routeRepository;
        private readonly IProduceScheduleRepository _scheduleRepository;
        private readonly ISigerProjectLevelSectionRepository _sectionRepository;
        private readonly ISigerProjectUserRepository _projectUserRepository;
        private readonly IWorkingGroupRepository _groupRepository;
        private readonly ISigerProjectProductRepository _productRepository;
        private readonly ISigerProjectMachineRepository _machineRepository;
        public ProductJobController(IProductPlanDetailRepository planDetailRepository, IProductPlanRepository planRepository,
            IProductRouteRepository routeRepository, IProduceScheduleRepository scheduleRepository,
            ISigerProjectLevelSectionRepository sectionRepository, ISigerProjectUserRepository projectUserRepository,
            IWorkingGroupRepository groupRepository, ISigerProjectProductRepository productRepository, ISigerProjectMachineRepository machineRepository,
            IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
            _planDetailRepository = planDetailRepository;
            _planRepository = planRepository;
            _routeRepository = routeRepository;
            _scheduleRepository = scheduleRepository;
            _sectionRepository = sectionRepository;
            _projectUserRepository = projectUserRepository;
            _groupRepository = groupRepository;
            _productRepository = productRepository;
            _machineRepository = machineRepository;
        }

        [HttpGet]
        public IActionResult GetPlanListForJob(string product_name, string draw_number, string code, string ordernumber, string status, string startTime, string endTime,
            int page = 1, int pagesize = 10)
        {
            var dtStart = string.IsNullOrWhiteSpace(startTime) ? 0 : UnixTimeHelper.GetUnixByShortDate(startTime);
            var dtEnd = string.IsNullOrWhiteSpace(endTime) ? 0 : UnixTimeHelper.GetUnixByShortDate(endTime) + 86400 - 1;
            var data = _planRepository.GetPagedProductPlan(product_name, draw_number, code, ordernumber, status,0, dtStart,
                dtEnd, "", ProjectId, page, pagesize);

            var response = new List<ResponseGetProductPlan>();
            foreach (var plan in data.Data)
            {
                var batch = _planDetailRepository.GetList(m =>
                    m.planId == plan.id && m.status == (int)RowState.Valid && m.projectId == ProjectId).Count();

                var planInfo = Mapper<ResponseGetProductPlan, ResponseGetProductPlan>.Map(plan);
                planInfo.batch = batch;
                planInfo.un_schedule = plan.quantity;

                var lastRoute = _routeRepository
                    .GetList(q => q.productId == plan.product_id && q.status == (int) RowState.Valid)
                    .OrderByDescending(q => q.serialNumber).FirstOrDefault();
                var lastRouteId = lastRoute?.id ?? 0;
                var planDetails = _planDetailRepository.GetList(q => q.planId == plan.id && q.status == (int)RowState.Valid && q.levelId == lastRouteId);
                if (planDetails.Any())
                {
                    planInfo.plan_start = 0;
                    planInfo.plan_end = 0;
                    planInfo.has_schedule = planDetails.Sum(q => q.quantity);//只计算最后一道工序的排产数量
                    planInfo.un_schedule = (plan.quantity - planInfo.has_schedule) < 0
                        ? 0
                        : plan.quantity - planInfo.has_schedule;
                }

                var deliveryDate = UnixTimeHelper.ConvertStringDateTime(plan.delivery_time.ToString());
                planInfo.leaveDays = deliveryDate.Date.Subtract(DateTime.Now.Date).Days;

                response.Add(planInfo);
            }

            return new PagedObjectResult(response, data.Total, page, pagesize);
        }

        [HttpGet]
        public IActionResult GetRouteNumber(int planId, int route_id)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var response = new ResponseGetRouteInfo
            {
                unjob_quanlity = plan.quantity
            };
            var planDetails = _planDetailRepository.GetList(q =>
                q.planId == planId && q.levelId == route_id && q.status == (int)RowState.Valid && q.projectId == ProjectId).ToList();
            if (planDetails.Any())
            {
                response.unjob_quanlity = plan.quantity - planDetails.Sum(q => q.quantity);
                var lastplan = planDetails.OrderByDescending(q => q.id).First();
                var orderNumber = lastplan.orderNumber.Split("-");
                if (orderNumber.Length > 1)
                {
                    response.serial_number = orderNumber[orderNumber.Length - 1].ToInt() + 1;
                }
            }

            response.unjob_quanlity = response.unjob_quanlity < 0 ? 0 : response.unjob_quanlity;
            return new ObjectResult(response);
        }

        /// <summary>
        /// 派工
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult SaveJob([FromBody]RequestSaveJob request)
        {
            var plan = _planRepository.Get(request.planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var route = _routeRepository.Get(q => q.id == request.route_id && q.status == (int) RowState.Valid);
            if (route == null)
            {
                throw new BadRequestException(RequestEnum.RouteNotFound);
            }

            var planDetail = new siger_project_product_plan_detail
            {
                addTime = DateTime.Now,
                levelId = request.route_id,
                startTime = 0,
                endTime = 0,
                orderNumber = request.order_number,
                planId = request.planId,
                projectId = ProjectId,
                quantity = request.count,
                operator_mid = request.operator_mid,
                creator_mid = UserId,
                remark = request.remark.ToStr()
            };
            _planDetailRepository.Insert(planDetail);
            _unitOfWork.Commit();
            var entity = new siger_project_produce_schedule
            {
                addTime = DateTime.Now,
                endTime = 0,
                projectId = ProjectId,
                sectionId = request.machine_id,
                startTime = 0,
                plandetail_id = planDetail.id,
                cycle_time = 0,
                route_name = route.name,
                working_hours = request.working_hours.ToDouble(),
                prepare = request.prepare.ToDouble()
            };
            _scheduleRepository.Insert(entity);

            plan.status = (int)PlanProcess.HasPlan;
            _planRepository.Update(plan);

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 派工进度一览
        /// </summary>
        /// <param name="planId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetOrderProgress(int planId)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var responses = new List<ResponseOrderProgress>();

            var planDetails = _planDetailRepository.GetList(q =>
                q.planId == planId && q.status == (int) RowState.Valid && q.projectId == ProjectId).ToList();
            var routes = _routeRepository.GetList(q => q.projectId == ProjectId && q.productId == plan.product_id && q.status == (int) RowState.Valid)
                .OrderBy(m => m.serialNumber).ToList();
            foreach (var route in routes)
            {
                var routeDetails = planDetails.Where(q => q.levelId == route.id);
                var response = new ResponseOrderProgress
                {
                    serialNumber = route.serialNumber,
                    description = route.description,
                    name = route.name,
                    unjob_count = 0,
                    plan_count = plan.quantity
                };
                if (routeDetails.Any())
                {
                    response.job_count = routeDetails.Sum(m => m.quantity);
                    response.finish_count = routeDetails.Sum(q => q.ok_number + q.nok_number);
                    response.state = plan.status;
                }
                else
                {
                    response.job_count = 0;
                    response.finish_count = 0;
                    response.state = 0;
                }
                responses.Add(response);
            }

            return new ObjectResult(responses);
        }

        [HttpGet]
        public IActionResult GetOrdersByPlan(int planId)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var routes = _routeRepository.GetList(q =>
                q.productId == plan.product_id && q.status == (int) RowState.Valid && q.projectId == ProjectId);
            if (!routes.Any())
            {
                throw new BadRequestException(RequestEnum.RouteNotFound);
            }

            var responses = new List<ResponseGetOrdersByPlan>();
            var planDetails = _planDetailRepository.GetList(q =>
                q.planId == planId && q.status == (int)RowState.Valid && q.projectId == ProjectId);
            foreach (var planDetail in planDetails.OrderBy(m => m.levelId).ToList())
            {
                var route = routes.FirstOrDefault(q => q.id == planDetail.levelId);
                if (route != null)
                {
                    responses.Add(new ResponseGetOrdersByPlan
                    {
                        planDetailId = planDetail.id,
                        route_id = route.id,
                        route_name = route.name ,
                        order_number = planDetail.orderNumber
                    });
                }
            }
            return new ObjectResult(responses);
        }

        /// <summary>
        /// 打印工单
        /// </summary>
        /// <param name="planDetailId"></param>
        /// <param name="routeId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult PrintScheduleByRouteId(int planDetailId, int routeId)
        {
            var route = _routeRepository.Get(q => q.id == routeId && q.status == (int)RowState.Valid);
            if (route == null)
            {
                throw new BadRequestException(RequestEnum.RouteNotFound);
            }

            var planDetail = _planDetailRepository.Get(q => q.id == planDetailId && q.status == (int) RowState.Valid && q.projectId == ProjectId);
            if (planDetail == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var plan = _planRepository.Get(planDetail.planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var schedule = _scheduleRepository.Get(q =>
                q.route_name == route.name && q.plandetail_id == planDetail.id && q.projectId == ProjectId
                && q.status == (int) RowState.Valid);
            if (schedule == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var machine = _sectionRepository.Get(q => q.id == schedule.sectionId && q.projectid == ProjectId);
            var user = _projectUserRepository.Get(q => q.mid == planDetail.operator_mid && q.projectid == ProjectId);
            var creator_user = _projectUserRepository.Get(q => q.mid == planDetail.creator_mid && q.projectid == ProjectId);
            var group = _groupRepository.Get(q => (q.user_mids + ",").Contains(planDetail.operator_mid + ",") && q.status == (int) RowState.Valid && q.project_id == ProjectId);
            var workGroupName = group?.name ?? "";
            var response = new ResponseScheduleByRouteId
            {
                date = planDetail.addTime.ToString(ParameterConstant.DateFormat),
                code = plan.code,
                draw_code = plan.draw_number,
                product_name = plan.product_name,
                route_name = route.name,
                working_hours = schedule.working_hours.ToStr(),
                order_number = plan.ordernumber,
                quantity = planDetail.quantity.ToStr(),
                machine_name = machine == null ? "" : machine.title,
                operator_name = user == null ? "" : user.name,
                creator_name = creator_user == null ? "" : creator_user.name,
                workgroup = workGroupName,
                prepare = schedule.prepare.ToStr(),
                remark = planDetail.remark.ToStr()
            };

            return new ObjectResult(response);
        }

        /// <summary>
        /// 可终止派工一览
        /// </summary>
        /// <param name="planId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetOrderProgressForStop(int planId)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var responses = new List<ResponseOrderProgressForStop>();

            var planDetails = _planDetailRepository.GetList(q =>
                q.planId == planId && q.status == (int)RowState.Valid && q.projectId == ProjectId).ToList();
            var plandetailIds = planDetails.Select(m => m.id).ToList();
            var schedules = _scheduleRepository.GetList(q => q.projectId == ProjectId && plandetailIds.Contains(q.plandetail_id) && q.status == (int)RowState.Valid)
                .ToList();
            foreach (var schedule in schedules)
            {
                var planDetail = planDetails.FirstOrDefault(q => q.id == schedule.plandetail_id);
                if (planDetail == null)
                {
                    continue;
                }
                var response = new ResponseOrderProgressForStop
                {
                    id = schedule.plandetail_id,
                    product_name = plan.product_name,
                    number = planDetail.orderNumber,
                    time = schedule.addTime.ToString(ParameterConstant.DateTimeFormat),
                    route_name = schedule.route_name
                };
                responses.Add(response);
            }
            return new ObjectResult(responses);
        }

        /// <summary>
        /// 终止排程
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult StopSchedule([FromBody]RequestStopSchedule request)
        {
            if (request.ids == null || !request.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }

            foreach (var id in request.ids)
            {
                var planDetail = _planDetailRepository.Get(q => q.id == id);
                if (planDetail != null)
                {
                    planDetail.status = (int) RowState.Invalid;
                }
                _planDetailRepository.Update(planDetail);

                var schedules = _scheduleRepository.GetList(q => q.plandetail_id == planDetail.id).ToList();
                foreach (var schedule in schedules)
                {
                    schedule.status = (int)RowState.Invalid;
                    _scheduleRepository.Update(schedule);
                }
            }

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 计划外派工
        /// </summary>
        /// <param name="product_name"></param>
        /// <param name="code"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="page"></param>
        /// <param name="pagesize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetNoPlanListForJob(string product_name, string code, string startTime, string endTime,
           int page = 1, int pagesize = 10)
        {
            var data = _planRepository.GetPagedProductNoPlan(product_name, code, startTime, endTime, ProjectId, page, pagesize);

            return new PagedObjectResult(data.Data, data.Total, page, pagesize);
        }

        [HttpPost]
        public IActionResult AddNoPlanJob([FromBody]RequestSaveNoPlanJob request)
        {
            var route = _routeRepository.Get(q => q.id == request.route_id && q.status == (int)RowState.Valid);
            if (route == null)
            {
                throw new BadRequestException(RequestEnum.RouteNotFound);
            }

            //检查设备
            var machineData = _machineRepository.GetMachineBySectionId(request.machine_id, ProjectId);
            if (machineData == null)
            {
                throw new BadRequestException(RequestEnum.MachineNotFound);
            }

            //生成工单号
            var pre = $"H{DateTime.Now:yyyyMMdd}";
            var number = pre + "-001";
            var details = _planDetailRepository.GetList(q => q.planId == 0 && q.projectId == ProjectId && q.addTime.Date == DateTime.Now.Date)
                .OrderByDescending(q => q.addTime).FirstOrDefault();
            if (details != null)
            {
                var numbers = details.orderNumber.Split('-');
                if (numbers.Length == 2)
                {
                    number = pre + "-" + (numbers[1].ToInt() + 1).ToString("000");
                }
            }

            var planDetail = new siger_project_product_plan_detail
            {
                addTime = DateTime.Now,
                levelId = request.product_id,
                startTime = 0,
                endTime = 0,
                orderNumber = number,
                planId = 0,
                projectId = ProjectId,
                quantity = request.count,
                operator_mid = request.operator_mid,
                creator_mid = UserId,
                remark = request.remark.ToStr()
            };
            _planDetailRepository.Insert(planDetail);
            _unitOfWork.Commit();
            var entity = new siger_project_produce_schedule
            {
                addTime = DateTime.Now,
                endTime = 0,
                projectId = ProjectId,
                sectionId = request.machine_id,
                startTime = 0,
                plandetail_id = planDetail.id,
                cycle_time = 0,
                route_name = route.name,
                working_hours = request.working_hours.ToDouble(),
                prepare = request.prepare.ToDouble()
            };
            _scheduleRepository.Insert(entity);

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult StopNoPlanJob([FromBody]RequestStopSchedule request)
        {
            if (request.ids == null || !request.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }

            foreach (var id in request.ids)
            {
                var planDetail = _planDetailRepository.Get(q => q.id == id);
                if (planDetail != null)
                {
                    planDetail.status = (int)RowState.Invalid;
                }
                _planDetailRepository.Update(planDetail);

                var schedules = _scheduleRepository.GetList(q => q.plandetail_id == planDetail.id).ToList();
                foreach (var schedule in schedules)
                {
                    schedule.status = (int)RowState.Invalid;
                    _scheduleRepository.Update(schedule);
                }
            }

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpGet]
        public IActionResult PrintNoPlanJob(int planDetailId)
        {
            var planDetail = _planDetailRepository.Get(q => q.id == planDetailId && q.status == (int)RowState.Valid && q.projectId == ProjectId);
            if (planDetail == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var schedule = _scheduleRepository.Get(q => q.plandetail_id == planDetail.id && q.projectId == ProjectId
                && q.status == (int)RowState.Valid);
            if (schedule == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var product = _productRepository.Get(q =>
                q.id == planDetail.levelId && q.projectid == ProjectId && q.status == (int) RowState.Valid);
            var machine = _sectionRepository.Get(q => q.id == schedule.sectionId && q.projectid == ProjectId);
            var user = _projectUserRepository.Get(q => q.mid == planDetail.operator_mid && q.projectid == ProjectId);
            var creatorUser = _projectUserRepository.Get(q => q.mid == planDetail.creator_mid && q.projectid == ProjectId);
            var response = new ResponseScheduleByRouteId
            {
                date = planDetail.addTime.ToString(ParameterConstant.DateFormat),
                code = planDetail.orderNumber,
                draw_code = product != null ? product.drawingcode : "",
                product_name = product != null? product.name : "",
                route_name = schedule.route_name,
                working_hours = schedule.working_hours.ToStr(),
                quantity = planDetail.quantity.ToStr(),
                machine_name = machine == null ? "" : machine.title,
                operator_name = user == null ? "" : user.name,
                creator_name = creatorUser == null ? "" : creatorUser.name,
                prepare = schedule.prepare.ToStr(),
                remark = planDetail.remark.ToStr()
            };

            return new ObjectResult(response);
        }
    }
}