using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver.Core.Operations;
using Siger.ApiCommon.Result;
using Siger.ApiCommon.Utilities;
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.AppSettings;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.ApiCNC.Controllers
{
    public class WorkingSignController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly ISigerProjectMachineRepository _machineRepository;
        private readonly IWorkingStateRepository _stateRepository;
        private readonly IWorkingSignRepository _workingSignRepository;
        private readonly ISigerProjectUserRepository _projectUserRepository;
        private readonly IProductPlanDetailRepository _productPlanDetailRepository;
        private readonly ISigerProjectProductReport _projectProductReport;
        private readonly IMachineCurrentStateRepository _currentStateRepository;
        private readonly IProductionBeatSetRepository _beatSetRepository;
        private readonly IWorkingGroupRepository _workingGroupRepository;
        private readonly IProduceScheduleRepository _scheduleRepository;
        public WorkingSignController(IUnitOfWork unitOfWork , IWorkingStateRepository stateRepository, ISigerProjectMachineRepository machineRepository,
            IWorkingSignRepository workingSignRepository, ISigerProjectUserRepository projectUserRepository, IProductPlanDetailRepository productPlanDetailRepository,
            ISigerProjectProductReport projectProductReport, IMachineCurrentStateRepository currentStateRepository, IProductionBeatSetRepository beatSetRepository,
            IWorkingGroupRepository workingGroupRepository, IProduceScheduleRepository scheduleRepository)
        {
            _unitOfWork = unitOfWork;
            _stateRepository = stateRepository;
            _machineRepository = machineRepository;
            _workingSignRepository = workingSignRepository;
            _projectUserRepository = projectUserRepository;
            _productPlanDetailRepository = productPlanDetailRepository;
            _projectProductReport = projectProductReport;
            _currentStateRepository = currentStateRepository;
            _beatSetRepository = beatSetRepository;
            _workingGroupRepository = workingGroupRepository;
            _scheduleRepository = scheduleRepository;
        }

        /// <summary>
        /// APP签到扫码
        /// </summary>
        /// <param name="machineid"></param>
        /// <param name="sectionid"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetSignInMachine(string machineid, string sectionid)
        {
            var machineId = machineid.ToInt();
            var sectionId = sectionid.ToInt();
            var machines = GetMachineDatas(machineId, sectionId).ToList();

            var machineIds = machines.Select(t => t.machine_id).ToList();
            var signs = _workingSignRepository.GetList(t => machineIds.Contains(t.machine_id) && t.project_id == ProjectId && 
                    t.status == (int)RowState.Valid && t.sign_outtime == DateTime.MinValue).ToList();

            var res = new ResponseGetSignMachine();
            var signMachines = new List<SignMachine>();
            foreach (var machine in machines)
            {
                var sign = signs.FirstOrDefault(t => t.machine_id == machine.machine_id);
                var userName = "";
                if (sign != null)
                {
                    var user = _projectUserRepository.Get(t => t.mid == sign.user_mid && t.projectid == ProjectId && t.status == (int) RowState.Valid);
                    userName = user?.name ?? "";
                }

                var model = new SignMachine
                {
                    machineid = machine.machine_id,
                    location = _machineRepository.GetMachineLocationBySectionId(machine.section_id, ProjectId),
                    machinename = machine.machine_name,
                    username = userName
                };
                signMachines.Add(model);
            }

            res.machines = signMachines;

            return new ObjectResult(res);
        }

        private IEnumerable<MachineData> GetMachineDatas(int machineId, int sectionId)
        {
            var machines = new List<MachineData>();
            if (machineId > 0)
            {
                var machine = _machineRepository.Get(t => t.projectid == ProjectId && t.status == (int)RowState.Valid && t.id == machineId);
                if (machine != null)
                {
                    var section = _machineRepository.GetSectionByMachineId(machine.id, ProjectId);
                    machines.Add(new MachineData
                    {
                        machine_id = machine.id,
                        machine_name = machine.title,
                        section_id = section?.id ?? 0,
                        machine_code = machine.code
                    });
                }
            }
            else if (sectionId > 0)
            {
                machines = _machineRepository.GetLevelSectionMachines(sectionId, ProjectId).ToList();
            }

            if (!machines.Any())
            {
                throw new BadRequestException(RequestEnum.MachineNotFound);
            }

            return machines;
        }

        /// <summary>
        /// APP签到
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult WorkSignIn([FromBody]RequestSelectMachines req)
        {
            if (!req.machines.Any())
            {
                throw new BadRequestException(RequestEnum.MachineNotFound);
            }

            var machineIds = req.machines.ToList();

            var signIns = _workingSignRepository.GetList(t => machineIds.Contains(t.machine_id) && t.project_id == ProjectId &&
                    t.status == (int)RowState.Valid && t.sign_outtime == DateTime.MinValue && t.user_mid == UserId);
            if (signIns.Any())
            {
                throw new BadRequestException(RequestEnum.SomeMachineNotSignOut);
            }

            var signs = _workingSignRepository.GetList(t => machineIds.Contains(t.machine_id) && t.project_id == ProjectId && 
                    t.status == (int)RowState.Valid && t.sign_outtime == DateTime.MinValue && t.user_mid != UserId).ToList();
            if (signs.Any())
            {
                foreach (var sign in signs)
                {
                    sign.sign_outtime = DateTime.Now;
                    _workingSignRepository.Update(sign);
                }                
            }

            foreach (var mId in machineIds)
            {
                var inSign = new siger_project_working_sign
                {
                    machine_id = mId,
                    project_id = ProjectId,
                    sign_intime = DateTime.Now,
                    sign_outtime = DateTime.MinValue,
                    user_mid = UserId
                };
                _workingSignRepository.Insert(inSign);
            }

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

        /// <summary>
        /// APP获取签出设备
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetSignOutMachine()
        {
            var signs = _workingSignRepository.GetList(t => t.project_id == ProjectId && 
                    t.status == (int)RowState.Valid && t.sign_outtime == DateTime.MinValue && t.user_mid == UserId).ToList();

            var machineIds = signs.Select(t => t.machine_id).Distinct().ToList();
            var machines = _machineRepository.GetList(t =>
                machineIds.Contains(t.id) && t.projectid == ProjectId && t.status == (int) RowState.Valid).ToList();
            var res = new ResponseGetSignOutMachine();
            var signMachines = new List<SignOutMachine>();
            foreach (var machine in machines)
            {
                var sign = signs.FirstOrDefault(t => t.machine_id == machine.id);
                if (sign == null)
                {
                    continue;
                }

                signMachines.Add(new SignOutMachine
                {
                    location = _machineRepository.GetMachineLocationByMachineId(machine.id, ProjectId),
                    machinecode = machine.code,
                    machineid = machine.id,
                    machinename = machine.title,
                    signtime = sign.sign_intime.ToString(ParameterConstant.DateTimeFormat),
                    totaltime = Math.Round((DateTime.Now - sign.sign_intime).TotalSeconds)
                });
            }

            res.mchines = signMachines;
            return new ObjectResult(res);
        }

        /// <summary>
        /// APP签出
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult WorkSignOut([FromBody]RequestSelectMachines req)
        {
            if (!req.machines.Any())
            {
                throw new BadRequestException(RequestEnum.MachineNotFound);
            }

            var machineIds = req.machines.ToList();

            var signs = _workingSignRepository.GetList(t => machineIds.Contains(t.machine_id) && t.project_id == ProjectId && 
                    t.status == (int)RowState.Valid && t.sign_outtime == DateTime.MinValue && t.user_mid == UserId).ToList();
            if (signs.Any())
            {
                foreach (var sign in signs)
                {
                    sign.sign_outtime = DateTime.Now;
                    _workingSignRepository.Update(sign);
                }
            }

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

        /// <summary>
        /// APP获取签到设备工单
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetSignOrders([FromBody]RequestGetSignMachineOrders req)
        {
            var res = new List<ResponseGetSignOrders>();
            var machineIds = new List<int>();
            DateTime startTime;
            DateTime endTime;

            var signs = new List<siger_project_working_sign>();
            if (req.machineid.ToInt() > 0)
            {
                var machine = _machineRepository.Get(t =>
                        t.id == req.machineid.ToInt() && t.projectid == ProjectId && t.status == (int)RowState.Valid);
                if (machine == null)
                {
                    throw new BadRequestException(RequestEnum.MachineNotFound);
                }
                signs = _workingSignRepository.GetList(t =>
                        t.project_id == ProjectId && t.status == (int)RowState.Valid && t.user_mid == UserId &&
                        t.sign_outtime == DateTime.MinValue && t.machine_id == machine.id).ToList();
                if (!signs.Any())
                {
                    return new ObjectResult(res);
                }
                machineIds.Add(machine.id);
                if (string.IsNullOrEmpty(req.starttime) || string.IsNullOrEmpty(req.endtime))
                {
                    var sign = signs.First();
                    startTime = sign.sign_intime;
                    endTime = DateTime.Now;
                }
                else
                {
                    startTime = req.starttime.ToDateTime();
                    endTime = req.endtime.ToDateTime();
                }
            }
            else
            {
                signs = _workingSignRepository.GetList(t =>
                        t.project_id == ProjectId && t.status == (int) RowState.Valid && t.user_mid == UserId && 
                        t.sign_outtime == DateTime.MinValue).ToList();
                machineIds = signs.Select(t => t.machine_id).ToList();
                if (!signs.Any())
                {
                    return new ObjectResult(res);
                }
                if (string.IsNullOrEmpty(req.starttime) || string.IsNullOrEmpty(req.endtime))
                {
                    startTime = signs.OrderBy(t => t.sign_intime).First().sign_intime;
                    endTime = DateTime.Now;
                }
                else
                {
                    startTime = req.starttime.ToDateTime();
                    endTime = req.endtime.ToDateTime();
                }
            }

            var stime = (int)UnixTimeHelper.ConvertDataTimeLong(startTime);
            var etime = (int)UnixTimeHelper.ConvertDataTimeLong(endTime);

            var workCode = _projectUserRepository.Get(t => t.mid == UserId)?.work_code ?? "";
            var reports = _projectProductReport.GetList(t => t.time <= etime && t.time >= stime && t.worker_code == workCode &&
                    t.projectid == ProjectId && t.status == (int) RowState.Valid && machineIds.Contains(t.machineid)).ToList();
            var planIds = reports.Select(t => t.plan_id).ToList();
            if (!planIds.Any())
            {
                return new ObjectResult(res);
            }
            var plans = _productPlanDetailRepository.GetSignPlans(0, 0, planIds, ProjectId).ToList();
            var machines = _machineRepository.GetList(t =>
                    machineIds.Contains(t.id) && t.projectid == ProjectId && t.status == (int) RowState.Valid).ToList();
            
            foreach (var plan in plans)
            {
                var machineReports = new List<MachineReport>();
                var report = reports.Where(t => t.code == plan.orderNumber).ToList();
                if (!report.Any())
                {
                    continue;
                }

                foreach (var r in report)
                {
                    var sign = signs.FirstOrDefault(t => t.machine_id == r.machineid);
                    if (sign == null || UnixTimeHelper.ConvertDataTimeLong(sign.sign_intime) > r.time)
                    {
                        continue;
                    }
                    var machine = machines.FirstOrDefault(t => t.id == r.machineid);
                    machineReports.Add(new MachineReport
                    {
                        machine = machine?.title ?? "",
                        nokcount = r.nok_number,
                        okcount = r.actual_output,
                        reporttime = UnixTimeHelper.ConvertIntDateTime(r.time)
                    });
                }

                if (!machineReports.Any())
                {
                    continue;
                }

                res.Add(new ResponseGetSignOrders
                {
                    DeliveryTime = UnixTimeHelper.ConvertIntDateTime(plan.delivery_time),
                    OrderNumber = plan.orderNumber,
                    FinishCount = plan.producted_number,
                    NokCount = plan.nok_number,
                    PassRate = Math.Round(
                        plan.ok_number > 0 ? plan.ok_number / (double) (plan.producted_number) * 100 : 0, 2),
                    PlanCount = plan.quantity,
                    ProductName = plan.product_name,
                    Status = plan.status,
                    ReportCount = report.Sum(t => t.actual_output + t.nok_number),
                    MachineReports = machineReports
                });
            }

            return new ObjectResult(res);
        }

        /// <summary>
        /// 打卡记录表
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetSignRecord([FromBody]RequestGetSignRecord req)
        {
            var sectionId = req.sectionid.ToInt();
            var departId = req.departid.ToInt();
            var groupId = req.groupid.ToInt();
            var userId = req.userid.ToInt();

            var machineIds = _machineRepository.GetMachinIdsBySectionId(sectionId, 0, ProjectId).ToList();
            var sectionIds = _machineRepository.GetSectionIdsByMahcineIds(machineIds, ProjectId).ToList();
            string stime;
            string etime;
            if (string.IsNullOrWhiteSpace(req.starttime) || string.IsNullOrWhiteSpace(req.endtime))
            {
                stime = DateTime.Now.ToString(ParameterConstant.MouthFirstDay);
                etime = DateTime.Now.ToString(ParameterConstant.DateTimeFormat);
            }
            else
            {
                stime = req.starttime;
                etime = req.endtime;
            }
            var data = _workingSignRepository.GetPagedList(machineIds, sectionIds, departId, 0, groupId, userId, stime,
                etime, ProjectId, req.page, req.pagesize, req.toexcel.ToInt());

            var res = new List<ResponseGetSignRecord>();
            foreach (var record in data.Data)
            {
                var model = Mapper<GetSignRecords, ResponseGetSignRecord>.Map(record);
                model.location = _machineRepository.GetMachineLocationByMachineId(model.machineid, ProjectId);
                model.totaltime = string.IsNullOrEmpty(model.endworktime)
                    ? (DateTime.Now - model.startworktime.ToDateTime()).TotalMinutes
                    : (model.endworktime.ToDateTime() - model.startworktime.ToDateTime()).TotalMinutes;
                model.totaltime = Math.Round(model.totaltime, 2);
                res.Add(model);
            }
            if(req.toexcel.ToInt() == 1)
            {
                return ExportSignRecord(res);
            }

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

        [HttpPost]
        private IActionResult ExportSignRecord(IEnumerable<ResponseGetSignRecord> response)
        {
            if (!response.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"SignRecordList{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<SignRecordList>();
            try
            {
                var list = new List<SignRecordList>();
                var index = 1;
                foreach (var model in response)
                {
                    var entity = new SignRecordList
                    {
                        No = index,
                        location = model.location,
                        workcode = model.workcode,
                        username = model.username,
                        departname = model.departname,
                        groupname = model.groupname,
                        stationname = model.stationname,
                        startworktime = model.startworktime,
                        endworktime = model.endworktime,
                        totaltime = Math.Round(model.totaltime / 60, 2)
                    };
                    list.Add(entity);
                    index++;
                }

                helper.GenerateExcel(list, fileName);
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportSignRecord failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        /// <summary>
        /// 员工工时统计
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UserWorkTimeCount([FromBody]RequestUserWorkTimeCount req)
        {
            var userId = req.userid.ToInt();
            var departId = req.departid.ToInt();
            var groupId = req.groupid.ToInt();
            var machineIds = _machineRepository.GetMachinIdsBySectionId(0, 0, ProjectId).ToList();
            var sectionIds = _machineRepository.GetSectionIdsByMahcineIds(machineIds, ProjectId).ToList();
            string stime;
            string etime;
            if (string.IsNullOrWhiteSpace(req.starttime) || string.IsNullOrWhiteSpace(req.endtime))
            {
                stime = DateTime.Now.ToString(ParameterConstant.MouthFirstDay);
                etime = DateTime.Now.ToString(ParameterConstant.DateTimeFormat);
            }
            else
            {
                stime = req.starttime;
                etime = req.endtime;
            }

            var st = stime.ToDateTime();
            var et = etime.ToDateTime();

            var signList = _workingSignRepository.GetSignList(machineIds, sectionIds, departId, 0, groupId, userId, stime, etime, ProjectId).ToList();
            var userIds = signList.Select(t => t.userid).Distinct().ToList();
            var res = new List<ResponseUserWorkTimeCount>();
            var now = DateTime.Now;
            var states = _stateRepository.GetList(t => t.state_type == 1 && t.project_id == ProjectId && t.status == (int) RowState.Valid)
                    .Select(t => t.state_code.ToInt()).ToList();
            var currentStates = _currentStateRepository.GetList(t => userIds.Contains(t.user_mid) && states.Contains(t.machine_state) && 
                    (t.start_time <= et && t.start_time >= st || t.end_time <= et && t.end_time >= st) &&
                    machineIds.Contains(t.machine_id) && t.project_id == ProjectId && t.status == (int) RowState.Valid).ToList();
            var sUnix = UnixTimeHelper.GetUnixByDate(stime);
            var eUnix = UnixTimeHelper.GetUnixByDate(etime);
            var users = _projectUserRepository.GetList(t => userIds.Contains(t.mid) && t.projectid == ProjectId && t.status == (int) RowState.Valid).ToList();
            var reports = _beatSetRepository.GetSignProductReport(sUnix, eUnix, machineIds, ProjectId).ToList();
            foreach (var userid in userIds)
            {
                var signs = signList.Where(t => t.userid == userid).OrderBy(t => t.signintime).ToList();
                var sign = signs.First();
                var model = new ResponseUserWorkTimeCount
                {
                    userid = userid,
                    workcode = sign.workcode,
                    departname = sign.departname,
                    groupname = sign.groupname,
                    username = sign.username,
                    stationname = sign.stationname
                };
                var machines = signs.Select(t => t.machineid).Distinct().ToList();

                double worktime = 0;//分
                double losstime = 0;//分

                var currentState = currentStates.Where(t => t.user_mid == userid).OrderBy(t => t.start_time).ToList();             
                foreach (var machine in machines)
                {
                    var records = signs.Where(t => t.machineid == machine).OrderBy(t => t.signintime).ToList();
                    foreach (var record in records)
                    {
                        var sDate = record.signintime;
                        var eDate = record.endworktime.ToDateTime();
                        if (st > sDate)
                        {
                            sDate = st;
                        }

                        if (string.IsNullOrEmpty(record.endworktime))
                        {
                            eDate = now;
                        }
                        else if(eDate > et)
                        {
                            eDate = et;
                        }
                        worktime += (eDate - sDate).TotalSeconds;
                        var stateRecords = currentState.Where(t => t.machine_id == machine && 
                                    (t.start_time <= eDate && t.start_time >= sDate || t.end_time <= eDate && t.end_time >= sDate)).OrderBy(t => t.start_time).ToList();
                        foreach (var stateRecord in stateRecords)
                        {
                            var sStateDate = stateRecord.start_time;
                            var eStateDate = stateRecord.end_time;
                            if (st > sStateDate)
                            {
                                sStateDate = st;
                            }

                            if (eStateDate == DateTime.MinValue)
                            {
                                eStateDate = now;
                            }
                            else if (eStateDate > et)
                            {
                                eStateDate = et;
                            }

                            if (eStateDate > eDate)
                            {
                                eStateDate = eDate;
                            }
                            if (sStateDate < sDate)
                            {
                                sStateDate = sDate;
                            }
                            losstime += (eStateDate - sStateDate).TotalSeconds;
                        }
                    }
                }

                var user = users.FirstOrDefault(t => t.mid == userid);
                var report = user == null ? new List<ProductReport>() : reports.Where(t => t.WorkCode == user.work_code).ToList();
                double efficiencytime = 0;//秒
                var reportMachines = report.Select(t => t.MachineId).Distinct().ToList();
                foreach (var machine in reportMachines)
                {
                    var reportSigns = signs.Where(t => t.machineid == machine);
                    foreach(var reportSign in reportSigns)
                    {
                        var sDate = reportSign.signintime;
                        var eDate = reportSign.endworktime.ToDateTime();
                        if (st > sDate)
                        {
                            sDate = st;
                        }
                        if (string.IsNullOrEmpty(reportSign.endworktime))
                        {
                            eDate = now;
                        }
                        else if (eDate > et)
                        {
                            eDate = et;
                        }

                        var unixsDate = UnixTimeHelper.ConvertDataTimeLong(sDate);
                        var unixeDate = UnixTimeHelper.ConvertDataTimeLong(eDate);
                        var signReport = report.Where(t => t.MachineId == machine && t.Time >= unixsDate && t.Time <= unixeDate).ToList();
                        efficiencytime += signReport.Sum(t => t.ActualOutput + t.NokNumber) * signReport.Sum(t => t.CycleTime + t.UpdownBesat);
                    }
                }

                model.worktime = Math.Round(worktime / 3600, 2);
                model.losstime = Math.Round(losstime / 3600, 2);
                model.efficiencytime = Math.Round(efficiencytime / 3600, 2);
                model.producttime = Math.Round((model.worktime - model.losstime) > 0 ? (model.worktime - model.losstime) : 0, 2);
                model.workefficiency = model.producttime > 0 ? Math.Round(model.efficiencytime / model.producttime * 100, 2) : 0;
                
                res.Add(model);
            }

            if (req.toexcel.ToInt() == 1)
            {
                return ExportUserWorkTimeCount(res);
            }
            var total = res.Count;
            res = res.Skip((req.page - 1) * req.pagesize).Take(req.pagesize).ToList();
            return new PagedObjectResult(res, total, req.page, req.pagesize);
        }

        [HttpPost]
        private IActionResult ExportUserWorkTimeCount(IEnumerable<ResponseUserWorkTimeCount> response)
        {
            if (!response.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"UserWorkTimeCount{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<UserWorkTimeList>();
            try
            {
                var list = new List<UserWorkTimeList>();
                var index = 1;
                foreach (var model in response)
                {
                    var entity = new UserWorkTimeList
                    {
                        No = index,
                        workcode = model.workcode,
                        username = model.username,
                        departname = model.departname,
                        groupname = model.groupname,
                        stationname = model.stationname,
                        worktime = model.worktime,
                        losstime = model.losstime,
                        producttime = model.producttime,
                        efficiencytime = model.efficiencytime,
                        workefficiency = model.workefficiency + "%"
                    };
                    list.Add(entity);
                    index++;
                }

                helper.GenerateExcel(list, fileName);
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportUserWorkTimeCount failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        /// <summary>
        /// 员工绩效分析
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult PerformanceAnalysis([FromBody]RequestPerformanceAnalysis req)
        {
            var userId = req.userid.ToInt();
            var departId = req.departid.ToInt();
            var groupId = req.groupid.ToInt();

            string stime;
            string etime;
            if (string.IsNullOrWhiteSpace(req.starttime) || string.IsNullOrWhiteSpace(req.endtime))
            {
                stime = DateTime.Now.ToString(ParameterConstant.MouthFirstDay);
                etime = DateTime.Now.ToString(ParameterConstant.DateTimeFormat);
            }
            else
            {
                stime = req.starttime;
                etime = req.endtime;
            }

            var st = stime.ToDateTime();
            var et = etime.ToDateTime();
            var sUnix = UnixTimeHelper.GetUnixByDate(stime);
            var eUnix = UnixTimeHelper.GetUnixByDate(etime);

            var machineIds = _machineRepository.GetMachinIdsBySectionId(0, 0, ProjectId).ToList();
            var sectionIds = _machineRepository.GetSectionIdsByMahcineIds(machineIds, ProjectId).ToList();
            var signList = _workingSignRepository.GetSignList(machineIds, sectionIds, departId, 0, groupId, userId, stime, etime, ProjectId).ToList();
            var userIds = signList.Select(t => t.userid).Distinct().ToList();
            var now = DateTime.Now;
            var states = _stateRepository
                    .GetList(t => t.state_type == 1 && t.project_id == ProjectId && t.status == (int)RowState.Valid)
                    .Select(t => t.state_code.ToInt()).ToList();
            var currentStates = _currentStateRepository.GetList(t =>
                    userIds.Contains(t.user_mid) && states.Contains(t.machine_state) &&
                    (t.start_time <= et && t.start_time >= st || t.end_time <= et && t.end_time >= st) &&
                    machineIds.Contains(t.machine_id) && t.project_id == ProjectId && t.status == (int)RowState.Valid).ToList();
            var users = _projectUserRepository.GetList(t =>
                    userIds.Contains(t.mid) && t.projectid == ProjectId && t.status == (int)RowState.Valid).ToList();
            var reports = _beatSetRepository.GetSignProductReport(sUnix, eUnix, machineIds, ProjectId)
                    .Where(t => users.Select(q => q.work_code).Contains(t.WorkCode)).ToList();

            var res = new ResponsePerformanceAnalysis();
            var xtype = req.xtype.ToInt();
            var ytype = req.ytype.ToInt();
            var x = new List<string>();
            var y = new List<double>();
            if(xtype == 0)//时间周期
            {
                var dataList = new List<DateWorkTimes>();
                var xid = req.datetype.ToInt();
                var interal = DateTimeHelper.GetInteral(xid);
                var dates = DateTimeHelper.GetDateTimes(st, et, xid);
                for (var i = 0; i < dates.Count; i++)
                {
                    var model = new DateWorkTimes();
                    DateTime start;
                    DateTime end;
                    if (xid == 0 || xid == 1)
                    {
                        start = dates[i];
                        end = dates[i].AddDays(interal).AddSeconds(-1) > DateTime.Now
                            ? DateTime.Now
                            : dates[i].AddDays(interal).AddSeconds(-1);
                        x.Add(start.ToString(ParameterConstant.DateFormat));
                        model.date = start.ToString(ParameterConstant.DateFormat);
                    }
                    else
                    {
                        start = dates[i].AddDays(1 - dates[i].Day);
                        end = dates[i].AddDays(1 - dates[i].Day).Date.AddMonths(1).AddSeconds(-1) > DateTime.Now
                            ? DateTime.Now
                            : dates[i].AddDays(1 - dates[i].Day).Date.AddMonths(1).AddSeconds(-1); //到月底
                        x.Add(start.ToString("yyyy-MM"));
                        model.date = start.ToString("yyyy-MM");
                    }

                    var signs = signList.Where(t => t.signintime <= end && t.signintime >= start || t.endworktime.ToDateTime() <= end &&
                                    t.endworktime.ToDateTime() >= start).OrderBy(t => t.signintime).ToList();
                    var machines = signs.Select(t => t.machineid).Distinct().ToList();

                    double worktime = 0;//分
                    double losstime = 0;//分

                    var currentState = currentStates.Where(t => t.start_time <= end && t.start_time >= start || t.end_time <= end &&
                                                                t.end_time >= start).OrderBy(t => t.start_time).ToList();
                    foreach (var machine in machines)
                    {
                        var records = signs.Where(t => t.machineid == machine).OrderBy(t => t.signintime).ToList();
                        foreach (var record in records)
                        {
                            var sDate = record.signintime;
                            var eDate = record.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }

                            if (string.IsNullOrEmpty(record.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }
                            worktime += (eDate - sDate).TotalSeconds;

                            var stateRecords = currentState.Where(t => t.machine_id == machine &&
                                                                       (t.start_time <= eDate && t.start_time >= sDate || t.end_time <= eDate && t.end_time >= sDate)).OrderBy(t => t.start_time).ToList();
                            foreach (var stateRecord in stateRecords)
                            {
                                var sStateDate = stateRecord.start_time;
                                var eStateDate = stateRecord.end_time;
                                if (sDate > sStateDate)
                                {
                                    sStateDate = sDate;
                                }

                                if (eStateDate == DateTime.MinValue)
                                {
                                    eStateDate = now;
                                }
                                else if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }

                                if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }
                                if (sStateDate < sDate)
                                {
                                    sStateDate = sDate;
                                }
                                losstime += (eStateDate - sStateDate).TotalSeconds;
                            }
                        }
                    }

                    var startUnix = UnixTimeHelper.ConvertDataTimeLong(start);
                    var endUnix = UnixTimeHelper.ConvertDataTimeLong(end);
                    var report = reports.Where(t=> t.Time >= startUnix && t.Time <= endUnix).ToList();
                    double efficiencytime = 0;//秒
                    var reportMachines = report.Select(t => t.MachineId).Distinct().ToList();
                    foreach (var machine in reportMachines)
                    {
                        var reportSigns = signs.Where(t => t.machineid == machine);
                        foreach(var reportSign in reportSigns)
                        {
                            var sDate = reportSign.signintime;
                            var eDate = reportSign.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }
                            if (string.IsNullOrEmpty(reportSign.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }

                            var unixsDate = UnixTimeHelper.ConvertDataTimeLong(sDate);
                            var unixeDate = UnixTimeHelper.ConvertDataTimeLong(eDate);
                            var signReport = report.Where(t => t.MachineId == machine && t.Time >= unixsDate && t.Time <= unixeDate).ToList();
                            efficiencytime += signReport.Sum(t => t.ActualOutput + t.NokNumber) * signReport.Sum(t => t.CycleTime + t.UpdownBesat);
                        }
                    }

                    worktime = Math.Round(worktime / 3600, 2);
                    losstime = Math.Round(losstime / 3600, 2);
                    efficiencytime = Math.Round(efficiencytime / 3600, 2);
                    var producttime = Math.Round((worktime - losstime) > 0 ? (worktime - losstime) : 0, 2);
                    var workefficiency = producttime > 0 ? Math.Round(efficiencytime / producttime * 100, 2) : 0;

                    if (ytype == 0)//效率
                    {
                        y.Add(workefficiency);
                    }
                    else if (ytype == 1)//作业
                    {
                        y.Add(worktime);
                    }
                    else if (ytype == 2)//损失
                    {
                        y.Add(losstime);
                    }
                    else if (ytype == 3)//有效
                    {
                        y.Add(efficiencytime);
                    }
                    else if (ytype == 4)//实际
                    {
                        y.Add(producttime);
                    }
                    model.number = i + 1;
                    model.workefficiency = workefficiency;
                    model.worktime = worktime;
                    model.producttime = producttime;
                    model.losstime = losstime;
                    model.efficiencytime = efficiencytime;
                    dataList.Add(model);
                }
                if (req.toexcel.ToInt() == 1)
                {
                    return ExportDateWorkTimes(dataList);
                }
                foreach (var data in dataList)
                {
                    res.datalist.Add(data);
                }
            }
            else if(xtype == 1)//班组
            {
                var dataList = new List<GroupWorkTimes>();
                var groupIds = new List<int>();
                if (groupId > 0)
                {
                    groupIds.Add(groupId);
                }
                else
                {
                    var gList = signList.Select(t => t.workgroupids).ToList();
                    foreach (var group in gList)
                    {
                        groupIds.AddRange(group);
                    }
                }             
                var groups = _workingGroupRepository.GetList(t => groupIds.Contains(t.id) && t.project_id == ProjectId && 
                        t.status == (int)RowState.Valid).ToList();
                var i = 1;
                foreach(var group in groups)
                {
                    var signs = signList.Where(t => t.workgroupids.Contains(group.id)).OrderBy(t => t.signintime).ToList();
                    var machines = signs.Select(t => t.machineid).Distinct().ToList();

                    double worktime = 0;//分
                    double losstime = 0;//分

                    var userids = signs.Select(t => t.userid).ToList();
                    var currentState = currentStates.Where(t => userids.Contains(t.user_mid)).OrderBy(t => t.start_time).ToList();
                    foreach (var machine in machines)
                    {
                        var records = signs.Where(t => t.machineid == machine).OrderBy(t => t.signintime).ToList();
                        foreach (var record in records)
                        {
                            var sDate = record.signintime;
                            var eDate = record.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }

                            if (string.IsNullOrEmpty(record.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }
                            worktime += (eDate - sDate).TotalSeconds;

                            var stateRecords = currentState.Where(t => t.machine_id == machine &&
                                                                       (t.start_time <= eDate && t.start_time >= sDate || t.end_time <= eDate && t.end_time >= sDate)).OrderBy(t => t.start_time).ToList();
                            foreach (var stateRecord in stateRecords)
                            {
                                var sStateDate = stateRecord.start_time;
                                var eStateDate = stateRecord.end_time;
                                if (sDate > sStateDate)
                                {
                                    sStateDate = sDate;
                                }

                                if (eStateDate == DateTime.MinValue)
                                {
                                    eStateDate = now;
                                }
                                else if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }

                                if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }
                                if (sStateDate < sDate)
                                {
                                    sStateDate = sDate;
                                }
                                losstime += (eStateDate - sStateDate).TotalSeconds;
                            }
                        }
                    }

                    var userMids = string.IsNullOrEmpty(group.user_mids) ? new List<int>() : group.user_mids.Split(',').Select(t => t.ToInt()).ToList();
                    var user = users.Where(t => userMids.Contains(t.mid)).ToList();
                    var report = reports.Where(t => user.Select(q => q.work_code).Contains(t.WorkCode)).ToList();
                    double efficiencytime = 0;//秒
                    var reportMachines = report.Select(t => t.MachineId).Distinct().ToList();
                    foreach (var machine in reportMachines)
                    {
                        var reportSigns = signs.Where(t => t.machineid == machine);
                        foreach(var reportSign in reportSigns)
                        {
                            var sDate = reportSign.signintime;
                            var eDate = reportSign.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }
                            if (string.IsNullOrEmpty(reportSign.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }

                            var unixsDate = UnixTimeHelper.ConvertDataTimeLong(sDate);
                            var unixeDate = UnixTimeHelper.ConvertDataTimeLong(eDate);
                            var signReport = report.Where(t => t.MachineId == machine && t.Time >= unixsDate && t.Time <= unixeDate).ToList();
                            efficiencytime += signReport.Sum(t => t.ActualOutput + t.NokNumber) * signReport.Sum(t => t.CycleTime + t.UpdownBesat);
                        }
                    }

                    worktime = Math.Round(worktime / 3600, 2);
                    losstime = Math.Round(losstime / 3600, 2);
                    efficiencytime = Math.Round(efficiencytime / 3600, 2);
                    var producttime = Math.Round((worktime - losstime) > 0 ? (worktime - losstime) : 0, 2);
                    var workefficiency = producttime > 0 ? Math.Round(efficiencytime / producttime * 100, 2) : 0;

                    x.Add(group.name);
                    if (ytype == 0)//效率
                    {
                        y.Add(workefficiency);
                    }
                    else if (ytype == 1)//作业
                    {
                        y.Add(worktime);
                    }
                    else if (ytype == 2)//损失
                    {
                        y.Add(losstime);
                    }
                    else if (ytype == 3)//有效
                    {
                        y.Add(efficiencytime);
                    }
                    else if (ytype == 4)//实际
                    {
                        y.Add(producttime);
                    }

                    dataList.Add(new GroupWorkTimes
                    {
                        number = i,
                        groupname = group.name,
                        workefficiency = workefficiency,
                        worktime = worktime,
                        efficiencytime = efficiencytime,
                        producttime = producttime,
                        losstime = losstime
                    });
                    i += 1;
                }
                if (req.toexcel.ToInt() == 1)
                {
                    return ExportGroupWorkTimes(dataList);
                }
                foreach (var data in dataList)
                {
                    res.datalist.Add(data);
                }
            }
            else if(xtype == 2)//人员
            {
                var dataList = new List<UserWorkTimes>();

                var i = 1;
                foreach (var userid in userIds)
                {
                    var user = users.First(t => t.mid == userid);
                    if (user == null)
                    {
                        continue;
                    }
                    var signs = signList.Where(t => t.userid == userid).OrderBy(t => t.signintime).ToList();
                    var machines = signs.Select(t => t.machineid).Distinct().ToList();

                    double worktime = 0;//分
                    double losstime = 0;//分

                    var currentState = currentStates.Where(t => t.user_mid == userid).OrderBy(t => t.start_time).ToList();
                    foreach (var machine in machines)
                    {
                        var records = signs.Where(t => t.machineid == machine).OrderBy(t => t.signintime).ToList();
                        foreach (var record in records)
                        {
                            var sDate = record.signintime;
                            var eDate = record.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }

                            if (string.IsNullOrEmpty(record.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }
                            worktime += (eDate - sDate).TotalSeconds;

                            var stateRecords = currentState.Where(t => t.machine_id == machine &&
                                                                       (t.start_time <= eDate && t.start_time >= sDate || t.end_time <= eDate && t.end_time >= sDate)).OrderBy(t => t.start_time).ToList();
                            foreach (var stateRecord in stateRecords)
                            {
                                var sStateDate = stateRecord.start_time;
                                var eStateDate = stateRecord.end_time;
                                if (sDate > sStateDate)
                                {
                                    sStateDate = sDate;
                                }

                                if (eStateDate == DateTime.MinValue)
                                {
                                    eStateDate = now;
                                }
                                else if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }

                                if (eStateDate > eDate)
                                {
                                    eStateDate = eDate;
                                }
                                if (sStateDate < sDate)
                                {
                                    sStateDate = sDate;
                                }
                                losstime += (eStateDate - sStateDate).TotalSeconds;
                            }
                        }
                    }

                    var report = reports.Where(t => t.WorkCode == user.work_code).ToList();
                    double efficiencytime = 0;//秒
                    var reportMachines = report.Select(t => t.MachineId).Distinct().ToList();
                    foreach (var machine in reportMachines)
                    {
                        var reportSigns = signs.Where(t => t.machineid == machine);
                        foreach(var reportSign in reportSigns)
                        {
                            var sDate = reportSign.signintime;
                            var eDate = reportSign.endworktime.ToDateTime();
                            if (st > sDate)
                            {
                                sDate = st;
                            }
                            if (string.IsNullOrEmpty(reportSign.endworktime))
                            {
                                eDate = now;
                            }
                            else if (eDate > et)
                            {
                                eDate = et;
                            }

                            var unixsDate = UnixTimeHelper.ConvertDataTimeLong(sDate);
                            var unixeDate = UnixTimeHelper.ConvertDataTimeLong(eDate);
                            var signReport = report.Where(t => t.MachineId == machine && t.Time >= unixsDate && t.Time <= unixeDate).ToList();
                            efficiencytime += signReport.Sum(t => t.ActualOutput + t.NokNumber) * signReport.Sum(t => t.CycleTime + t.UpdownBesat);
                        }
                    }

                    worktime = Math.Round(worktime / 3600, 2);
                    losstime = Math.Round(losstime / 3600, 2);
                    efficiencytime = Math.Round(efficiencytime / 3600, 2);
                    var producttime = Math.Round((worktime - losstime) > 0 ? (worktime - losstime) : 0, 2);
                    var workefficiency = producttime > 0 ? Math.Round(efficiencytime / producttime * 100, 2) : 0;                    
                    x.Add(user.name);
                    if (ytype == 0)//效率
                    {
                        y.Add(workefficiency);
                    }
                    else if (ytype == 1)//作业
                    {
                        y.Add(worktime);
                    }
                    else if (ytype == 2)//损失
                    {
                        y.Add(losstime);
                    }
                    else if (ytype == 3)//有效
                    {
                        y.Add(efficiencytime);
                    }
                    else if (ytype == 4)//实际
                    {
                        y.Add(producttime);
                    }

                    dataList.Add(new UserWorkTimes
                    {
                        number = i,
                        username = user.name,
                        workefficiency = workefficiency,
                        worktime = worktime,
                        efficiencytime = efficiencytime,
                        producttime = producttime,
                        losstime = losstime
                    });
                    i += 1;
                }
                if (req.toexcel.ToInt() == 1)
                {
                    return ExportUserWorkTimes(dataList);
                }
                foreach (var data in dataList)
                {
                    res.datalist.Add(data);
                }
            }

            res.x = x;
            res.y = y;

            return new ObjectResult(res);
        }

        [HttpPost]
        private IActionResult ExportDateWorkTimes(IEnumerable<DateWorkTimes> response)
        {
            if (!response.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"DateWorkTimes{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<DateWorkTimeCount>();
            try
            {
                var list = new List<DateWorkTimeCount>();
                var index = 1;
                foreach (var model in response)
                {
                    var entity = new DateWorkTimeCount
                    {
                        No = index,
                        date = model.date,
                        worktime = model.worktime,
                        losstime = model.losstime,
                        producttime = model.producttime,
                        efficiencytime = model.efficiencytime,
                        workefficiency = model.workefficiency + "%"
                    };
                    list.Add(entity);
                    index++;
                }

                helper.GenerateExcel(list, fileName);
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportDateWorkTimes failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        [HttpPost]
        private IActionResult ExportGroupWorkTimes(IEnumerable<GroupWorkTimes> response)
        {
            if (!response.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"GroupWorkTimes{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<GroupWorkTimeCount>();
            try
            {
                var list = new List<GroupWorkTimeCount>();
                var index = 1;
                foreach (var model in response)
                {
                    var entity = new GroupWorkTimeCount
                    {
                        No = index,
                        groupname = model.groupname,
                        worktime = model.worktime,
                        losstime = model.losstime,
                        producttime = model.producttime,
                        efficiencytime = model.efficiencytime,
                        workefficiency = model.workefficiency + "%"
                    };
                    list.Add(entity);
                    index++;
                }

                helper.GenerateExcel(list, fileName);
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportGroupWorkTimes failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        [HttpPost]
        private IActionResult ExportUserWorkTimes(IEnumerable<UserWorkTimes> response)
        {
            if (!response.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var temporaryFileName = $"UserWorkTimes{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<UserWorkTimeCount>();
            try
            {
                var list = new List<UserWorkTimeCount>();
                var index = 1;
                foreach (var model in response)
                {
                    var entity = new UserWorkTimeCount
                    {
                        No = index,
                        username = model.username,
                        worktime = model.worktime,
                        losstime = model.losstime,
                        producttime = model.producttime,
                        efficiencytime = model.efficiencytime,
                        workefficiency = model.workefficiency + "%"
                    };
                    list.Add(entity);
                    index++;
                }

                helper.GenerateExcel(list, fileName);
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportUserWorkTimes failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        /// <summary>
        /// 员工工时统计详情
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="starttime"></param>
        /// <param name="endtime"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetUserWorkTimeDetail(int userid, string starttime, string endtime)
        {
            var user = _projectUserRepository.Get(t => t.mid == userid && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if(user == null)
            {
                throw new BadRequestException(RequestEnum.UserNotFound);
            }

            string stime;
            string etime;
            if (string.IsNullOrWhiteSpace(starttime) || string.IsNullOrWhiteSpace(endtime))
            {
                stime = DateTime.Now.ToString(ParameterConstant.MouthFirstDay);
                etime = DateTime.Now.ToString(ParameterConstant.DateTimeFormat);
            }
            else
            {
                stime = starttime;
                etime = endtime;
            }

            var st = stime.ToDateTime();
            var et = etime.ToDateTime();
            var sUnix = UnixTimeHelper.GetUnixByDate(stime);
            var eUnix = UnixTimeHelper.GetUnixByDate(etime);
            var now = DateTime.Now;

            var machineIds = _machineRepository.GetMachinIdsBySectionId(0, 0, ProjectId).ToList();
            var sectionIds = _machineRepository.GetSectionIdsByMahcineIds(machineIds, ProjectId).ToList();
            var signList = _workingSignRepository.GetSignList(machineIds, sectionIds, 0, 0, 0, userid, stime, etime, ProjectId)
                    .OrderBy(t => t.signintime).ToList();
            var userIds = signList.Select(t => t.userid).Distinct().ToList();
            var states = _stateRepository.GetList(t => t.state_type == 1 && t.project_id == ProjectId && t.status == (int)RowState.Valid).ToList();
            var stateCodes = states.Select(t => t.state_code.ToInt()).ToList();
            var currentStates = _currentStateRepository.GetList(t => userIds.Contains(t.user_mid) && stateCodes.Contains(t.machine_state) &&
                    (t.start_time <= et && t.start_time >= st || t.end_time <= et && t.end_time >= st) &&
                    machineIds.Contains(t.machine_id) && t.project_id == ProjectId && t.status == (int)RowState.Valid).OrderBy(t => t.start_time).ToList();
            var users = _projectUserRepository.GetList(t =>
                    userIds.Contains(t.mid) && t.projectid == ProjectId && t.status == (int) RowState.Valid).ToList();
            var reports = _beatSetRepository.GetSignProductReport(sUnix, eUnix, machineIds, ProjectId)
                    .Where(t => users.Select(q => q.work_code).Contains(t.WorkCode))
                    .OrderBy(t => t.StartTime).ToList();

            var reqUser = _projectUserRepository.Get(t => t.mid == userid && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            var res = new ResponseGetUserWorkTimeDetail
            {
                workcode = reqUser?.work_code ?? "",
                username = reqUser?.name ?? "",
                timerange = stime + " ~ " + etime,
                shiftname = signList.FirstOrDefault()?.shiftname ?? ""
            };
            foreach (var sign in signList)
            {
                var eDate = string.IsNullOrEmpty(sign.endworktime) ? now : sign.endworktime.ToDateTime();
                res.SignRecords.Add(new SignCountRecord
                {
                    location = _machineRepository.GetMachineLocationByMachineId(sign.machineid, ProjectId),
                    startworktime = sign.startworktime,
                    endworktime = string.IsNullOrEmpty(sign.endworktime) ? "NA" : eDate.ToString(ParameterConstant.DateTimeFormat),
                    worktime = (eDate - sign.startworktime.ToDateTime()).TotalHours
                });
            }
            foreach (var state in currentStates)
            {
                var eDate = state.end_time == DateTime.MinValue ? now : state.end_time;
                var fault = states.FirstOrDefault(t => t.state_code.ToInt() == state.machine_state);
                res.FaultRecords.Add(new FaultCountRecord
                {
                    location = _machineRepository.GetMachineLocationByMachineId(state.machine_id, ProjectId),
                    faultname = fault?.state_name ?? "",
                    starttime = state.start_time.ToString(ParameterConstant.DateTimeFormat),
                    endtime = state.end_time == DateTime.MinValue ? "NA" : eDate.ToString(ParameterConstant.DateTimeFormat),
                    losstime = (eDate - state.start_time).TotalHours,
                    faultdetail = ""
                });
            }
            var planIds = reports.Select(t => t.PlanId).Distinct().ToList();
            var planDetails = _productPlanDetailRepository.GetList(t => planIds.Contains(t.planId) &&
                    t.projectId == ProjectId && t.status == (int)RowState.Valid).ToList();
            var planDetailIds = planDetails.Select(t => t.id).ToList();
            var schedules = _scheduleRepository.GetList(t => planDetailIds.Contains(t.plandetail_id) && 
                    t.projectId == ProjectId && t.status == (int)RowState.Valid).ToList();
            foreach(var report in reports)
            {
                var reportSigns = signList.Where(t => t.machineid == report.MachineId);
                if (!reportSigns.Any())
                {
                    continue;
                }
                foreach(var sign in reportSigns)
                {
                    var sDate = sign.signintime < st ? st : sign.signintime;
                    var eDate = string.IsNullOrEmpty(sign.endworktime) ? now : sign.endworktime.ToDateTime();
                    var unixsDate = UnixTimeHelper.ConvertDataTimeLong(sDate);
                    var unixeDate = UnixTimeHelper.ConvertDataTimeLong(eDate);
                    if (report.Time >= unixsDate && report.Time <= unixeDate)
                    {
                        var detailIds = planDetails.Where(t => t.planId == report.PlanId).Select(t => t.id).ToList();
                        var schedule = schedules.Where(t => detailIds.Contains(t.plandetail_id)).ToList();
                        res.ReportRecords.Add(new ReportCountRecord
                        {
                            location = _machineRepository.GetMachineLocationByMachineId(report.MachineId, ProjectId),
                            ordernumber = report.OrderNumber,
                            productname = report.ProductName,
                            routename = string.Join(',', schedule.Select(t => t.route_name).Distinct()),
                            oknumber = report.ActualOutput,
                            noknumber = report.NokNumber,
                            effiencytime = Math.Round((report.ActualOutput + report.NokNumber) * (report.CycleTime + report.UpdownBesat) / 3600, 2),
                            reporttime = report.ReportTime
                        });
                    }
                }
            }

            return new ObjectResult(res);
        }
    }
}