using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.ToolRepository.Entities;
using Siger.Middlelayer.ToolRepository.Repositories.Interface;
using Siger.Middlelayer.ToolRepository.Response;
using Siger.Middlelayer.Utility.ExcelImport;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.ToolRepository.Repositories
{
    internal class SigerToolChangeRecordRepository : ApiToolRepositoryBase<siger_tool_change_record>,
        ISigerToolChangeRecordRepository
    {
        ApiToolDbContext ToolDbContext;
        public SigerToolChangeRecordRepository(ApiToolDbContext context) : base(context)
        {
            ToolDbContext = context;
        }

        public IPagedCollectionResult<ToolChangeRecord> GetToolChangeRecord(int sectionId, int projectId, string toolName, 
            string toolDrawno, string reason, string userName, int page, int pagesize)
        {
            //根据最后一级leveID 获取machieID;
            var sectionMachies = GetMachineIds(sectionId, projectId);
            if (!sectionMachies.Any())
            {
                return new PagedCollectionResult<ToolChangeRecord>(new List<ToolChangeRecord>(), 0);
            }

            var toolChange = ToolDbContext.siger_tool_change_record.Where(q => q.status == (int) RowState.Valid && q.projectid == projectId);
            var query = from ch in toolChange
                        join mc in ToolDbContext.siger_project_machine on ch.equip_code equals mc.code into tbl2
                        from q2 in tbl2.DefaultIfEmpty()
                        join us in ToolDbContext.siger_project_user on ch.change_user equals us.mid.ToString() into temp1
                        from u in temp1.DefaultIfEmpty()
                        where sectionMachies.Contains(q2.id) && q2.projectid == projectId && q2.status == (int)RowState.Valid
                        select new ToolChangeRecord
                        {
                            id = ch.id,
                            equip_code = ch.equip_code,
                            equip_name = ch.equip_name,
                            mainaxis = ch.mainaxis,
                            tool_name = ch.tool_name,
                            tool_drawno = ch.tool_drawno,
                            tool_no = ch.tool_no,
                            rating_life = ch.rating_life ?? 0,
                            true_residual_life = ch.true_residual_life.ToString(),
                            residual_life=ch.residual_life.ToStr(),
                            change_user = u != null ? u.name : "",
                            change_reason = ch.change_reason,
                            change_time = ch.change_time == 0 ? "" : UnixTimeHelper.ConvertIntDateTime(ch.change_time),
                            programno = ch.programno,
                            comment = ch.comment,
                            url_path = ch.url_path,
                            machineId=q2.id
                        };
            Expression<Func<ToolChangeRecord, bool>> toolNameExpression = q => true;
            if (!string.IsNullOrEmpty(toolName))
            {
                toolNameExpression = q => q.tool_name == toolName;
            }
            Expression<Func<ToolChangeRecord, bool>> toolDrawnoExpression = q => true;
            if (!string.IsNullOrEmpty(toolDrawno))
            {
                toolDrawnoExpression = q => q.tool_drawno == toolDrawno;
            }
            Expression<Func<ToolChangeRecord, bool>> reasonExpression = q => true;
            if (!string.IsNullOrEmpty(reason))
            {
                reasonExpression = q => q.change_reason == reason;
            }
            Expression<Func<ToolChangeRecord, bool>> userNameExpression = q => true;
            if (!string.IsNullOrEmpty(userName))
            {
                userNameExpression = q => q.change_user == userName;
            }

            var predicate = toolNameExpression.And(toolDrawnoExpression).And(reasonExpression).And(userNameExpression);

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

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

        public IEnumerable<ToolChangeRecord> ExportToolChangeRecords(int sectionId, int projectId, string toolName, string toolDrawno, string reason, string userName)
        {
            var sectionMachies = GetMachineIds(sectionId, projectId);
            if (!sectionMachies.Any())
            {
                return new List<ToolChangeRecord>();
            }

            var toolChange = ToolDbContext.siger_tool_change_record.Where(q => q.status == (int)RowState.Valid && q.projectid == projectId);
            var query = from ch in toolChange
                        join mc in ToolDbContext.siger_project_machine on ch.equip_code equals mc.code into tbl2
                        from q2 in tbl2.DefaultIfEmpty()
                        join us in ToolDbContext.siger_project_user on ch.change_user equals us.mid.ToString() into temp1
                        from u in temp1.DefaultIfEmpty()
                        where sectionMachies.Contains(q2.id) && q2.projectid == projectId && q2.status == (int)RowState.Valid
                        select new ToolChangeRecord
                        {
                            id = ch.id,
                            equip_code = ch.equip_code,
                            equip_name = ch.equip_name,
                            mainaxis = ch.mainaxis,
                            tool_name = ch.tool_name,
                            tool_drawno = ch.tool_drawno,
                            tool_no = ch.tool_no,
                            rating_life = ch.rating_life ?? 0,
                            true_residual_life = ch.true_residual_life.ToString(),
                            change_user = u != null ? u.name : "",
                            change_reason = ch.change_reason,
                            change_time = ch.change_time.ToString(),
                            programno = ch.programno,
                            comment = ch.comment
                        };
            Expression<Func<ToolChangeRecord, bool>> toolNameExpression = q => true;
            if (!string.IsNullOrEmpty(toolName))
            {
                toolNameExpression = q => q.tool_name == toolName;
            }
            Expression<Func<ToolChangeRecord, bool>> toolDrawnoExpression = q => true;
            if (!string.IsNullOrEmpty(toolDrawno))
            {
                toolDrawnoExpression = q => q.tool_drawno == toolDrawno;
            }
            Expression<Func<ToolChangeRecord, bool>> reasonExpression = q => true;
            if (!string.IsNullOrEmpty(reason))
            {
                reasonExpression = q => q.change_reason == reason;
            }
            Expression<Func<ToolChangeRecord, bool>> userNameExpression = q => true;
            if (!string.IsNullOrEmpty(userName))
            {
                userNameExpression = q => q.change_user == userName;
            }

            var express = toolNameExpression.And(toolDrawnoExpression).And(reasonExpression).And(userNameExpression);
            return query.Where(express);
        }

        public List<ChangeToolInfo> GetToolLifeReport(int sectionid, int projectId, long startTime, long endTime, string toolName, int toolId)
        {
            var response = new List<ChangeToolInfo>();
            var machineIDs = GetMachineIds(sectionid, projectId);
            if (!machineIDs.Any())
            {
                return response;
            }

            var changeRecords = from q in ToolDbContext.siger_tool_change_record
                join t in ToolDbContext.siger_project_tool on q.tool_drawno equals t.drawingcode into temp1
                from tb1 in temp1.DefaultIfEmpty()
                where q.projectid == projectId
                      && q.change_time >= startTime && q.change_time <= endTime
                      && machineIDs.Contains(q.machine_id)
                select new ChangeToolInfo
                {
                    ratedlife = q.rating_life ?? 0,
                    residual_life = (q.rating_life ?? 0) - (q.true_residual_life ?? 0),
                    toolsupplier = q.supplier,
                    toolname = q.tool_name,
                    change_time = q.change_time,
                    tooldrawingcode = q.tool_drawno,
                    toolId = tb1 != null ? tb1.id: 0,
                    toolunitprice = tb1 != null ? (tb1.unitprice.HasValue ? decimal.Parse(tb1.unitprice.Value.ToString()) : 0) : 0
                };
            Expression<Func<ChangeToolInfo, bool>> toolNameExpression = q => true;
            if (!string.IsNullOrEmpty(toolName))
            {
                toolNameExpression = q => q.toolname.Contains(toolName);
            }

            Expression<Func<ChangeToolInfo, bool>> toolIdExpression = q => true;
            if (toolId > 0)
            {
                toolIdExpression = q => q.toolId == toolId;
            }

            var predicate = toolNameExpression.And(toolIdExpression);

            return changeRecords.Where(predicate).OrderBy(f => f.change_time).ToList();
        }

        public List<ResponseChangeUserList> GetChangeToolUser(int projectId)
        {
            var query = from c in ToolDbContext.siger_tool_change_record
                        join u in ToolDbContext.siger_project_user on c.projectid equals u.projectid
                        where c.projectid == projectId && c.status == (int)RowState.Valid
                              && u.projectid == projectId && u.status == (int)RowState.Valid
                        select new ResponseChangeUserList
                        {
                            change_user_name = u.name,
                            change_user_work_code = u.work_code
                        };
            return query.Distinct().ToList();
        }

        public List<MachineData> GetMachineList(int sectionId, int projectId)
        {
            var sections = GetSonLevelSectionIds(sectionId, projectId);
            var result = (from lsm in ToolDbContext.siger_project_machine_attribution
                          join m in ToolDbContext.siger_project_machine on lsm.machine equals m.id
                          where sections.Contains(lsm.station) && lsm.status == (int)RowState.Valid && m.category == (int)MachineCategory.NC
                          select new MachineData
                          {
                              machine_name = m.title,
                              machine_id = m.id,
                              machine_code = m.code
                          }).ToList();
            if (result.Count == 0)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            return result;
        }

        public ToolChangeImportResult ImportToolChange(IEnumerable<ToolChangeList> tooChanges, int projectId)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var machineIds = new List<int>();
            var toolIds = new List<int>();
            var userIds = new List<int>();
            foreach (var toolChange in tooChanges)
            {
                rowIndex++;
                var machineEntity = ToolDbContext.siger_project_machine.FirstOrDefault(q =>
                    q.code == toolChange.Code && q.status == (int) RowState.Valid && q.projectid == projectId);
                if (machineEntity == null)
                {
                    errors.Add($"{rowIndex},{(int) RequestEnum.MachineNotFound}");
                }
                else
                {
                    machineIds.Add(machineEntity.id);
                }

                var toolInfo = ToolDbContext.siger_project_tool.FirstOrDefault(q =>
                    q.drawingcode == toolChange.ToolDrawingCode && q.status == (int)RowState.Valid
                                                                  && q.projectid == projectId);
                //if (toolInfo == null)
                //{
                //    errors.Add($"{rowIndex},{(int)RequestEnum.ToolNotFound}");
                //}
                //else
                //{
                //    toolIds.Add(toolInfo.id);
                //}
                if (toolInfo!=null)
                {
                    toolIds.Add(toolInfo.id);
                }

                if (!string.IsNullOrWhiteSpace(toolChange.ChangeUser))
                {
                    var user = ToolDbContext.siger_project_user.FirstOrDefault(q =>
                        q.work_code == toolChange.ChangeUser && q.status == (int) RowState.Valid
                                                               && q.projectid == projectId);
                    if (user == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.UserNotFound}");
                        userIds.Add(0);
                    }
                    else
                    {
                        userIds.Add(user.mid);
                    }
                }
                else
                {
                    userIds.Add(0);
                }

                if (!ChangeToolReasonConverter.ChangeReasons.Values.Contains(toolChange.ChangeReason))
                {
                    errors.Add($"{rowIndex},{(int)ImportEnum.ChangeReasonNotFound}");
                }

                if (errors.Any())
                {
                    return new ToolChangeImportResult(0, string.Join(";", errors), null);
                }
            }
            var toolImportInfo = new List<ToolChangeImportInfo>();
            try
            {
                var toolChanges = tooChanges.ToList();
                for (int i = 0; i < toolChanges.Count; i++)
                {
                    var changeRecord = toolChanges[i];
                    var entity = new siger_tool_change_record
                    {
                        programno =changeRecord.ToolProcesPn,
                        equip_code = changeRecord.Code,
                        equip_name = changeRecord.Name,
                        machine_id = machineIds[i],
                        mainaxis = changeRecord.SpindleNo,
                        tool_no = changeRecord.ToolNo,
                        tool_name = changeRecord.ToolName,
                        tool_drawno = changeRecord.ToolDrawingCode,
                        rating_life = changeRecord.RateLife,
                        true_residual_life = changeRecord.RemainderLife,
                        change_time = (int)UnixTimeHelper.ConvertDataTimeLong(changeRecord.ChangeTime),
                        comment = changeRecord.Remark,
                        change_reason = ChangeToolReasonConverter.ChangeReasons.First(q => q.Value == changeRecord.ChangeReason).Key,
                        change_user = userIds[i].ToString(),
                        status = (int)RowState.Valid,
                        projectid = projectId,
                    };
                    ToolDbContext.siger_tool_change_record.AddRange(entity);
                    ToolDbContext.SaveChanges();

                    toolImportInfo.Add(new ToolChangeImportInfo
                    {
                        ChangeTime = entity.change_time,
                        MachineId = entity.machine_id,
                        ProgramNo = entity.programno,
                        RatedLife = changeRecord.RateLife,
                        Reason = entity.change_reason,
                        SpindleName = changeRecord.SpindleNo,
                        ToolName = changeRecord.ToolName,
                        ToolNo = changeRecord.ToolNo
                    });
                }
            }
            catch
            {
                throw;
            }

            return new ToolChangeImportResult(1, "1", toolImportInfo);
        }
        
    }
}