using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Exceptions;
using Siger.ApiCommon.Result;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.AppSettings;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.TpmRepository.Entities;
using Siger.Middlelayer.TpmRepository.Repositories.Interface;
using Siger.Middlelayer.TpmRepository.Request;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;
using EnumHelper = Siger.Middlelayer.Common.Helpers.EnumHelper;
using UnixTimeHelper = Siger.Middlelayer.Common.Helpers.UnixTimeHelper;

namespace Siger.ApiTPM.Controllers
{
    public class SparepartRecordController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly ISigerProjectMachineAttributionRepository _machineAttributionRepository;
        private readonly ISigerProjectLevelSectionRepository _projectLevelRepository;
        private readonly ISparepartRepository _sparepartRepository;
        private readonly ISparepartRecordRepository _recordRepository;
        private readonly IRepairRepository _repairRepository;
        private readonly ISigerProjectSparepartCodeRepository _codeRepository;
        public SparepartRecordController(ISparepartRecordRepository recordRepository, ISparepartRepository sparepartRepository,
            IRepairRepository repairRepository, ISigerProjectSparepartCodeRepository codeRepository, IUnitOfWork unitOfWork,
            ISigerProjectMachineAttributionRepository machineAttributionRepository, ISigerProjectLevelSectionRepository projectLevelRepository)
        {
            _unitOfWork = unitOfWork;
            _machineAttributionRepository = machineAttributionRepository;
            _projectLevelRepository = projectLevelRepository;
            _recordRepository = recordRepository;
            _sparepartRepository = sparepartRepository;
            _repairRepository = repairRepository;
            _codeRepository = codeRepository;
        }

        [HttpPost]
        public IActionResult SearchSparepartRecord([FromBody]RequestSearchSparepartRecord request)
        {
            var response = new List<ResponseGetSparepartRecord>();

            var startTime = 0;
            if (!string.IsNullOrWhiteSpace(request.startTime))
            {
                if (request.startTime.ToDateTime() != DateTime.MinValue)
                {
                    startTime = UnixTimeHelper.GetUnixByShortDate(request.startTime);
                }
            }

            var endTime = 0;
            if (!string.IsNullOrWhiteSpace(request.endTime))
            {
                if (request.endTime.ToDateTime() != DateTime.MinValue)
                {
                    endTime = UnixTimeHelper.GetUnixByShortDate(request.endTime);
                }
            }

            var machineIds = new List<int>();
            if (!string.IsNullOrWhiteSpace(request.machineIds))
            {
                foreach (var machineId in request.machineIds.Split(','))
                {
                    machineIds.Add(machineId.ToInt());
                }
            }
            var list = _recordRepository.GetPagedList(startTime, endTime, request.keyword,
                request.s_is_standard, request.s_is_substitute, request.skutype.ToInt(), request.inStockType.ToInt(), request.outStockType.ToInt(),
                request.link, machineIds, request.sparepart.ToInt(), ProjectId, request.page, request.pagesize);

            foreach (var sparepartRecord in list.Data)
            {
                var data = Mapper<SparepartRecord, ResponseGetSparepartRecord>.Map(sparepartRecord);
                data.location = sparepartRecord.machineId != 0 ?
                    string.Join('-', _repairRepository.GetParentLevelSections(sparepartRecord.machineId, ProjectId))
                    : string.Empty;

                var section = _machineAttributionRepository.Get(f => f.projectid == ProjectId && f.status != 0 && f.machine == sparepartRecord.machineId);
                if (section != null)
                {
                    var sections = _projectLevelRepository.GetParentLevelSections(section.station, ProjectId).OrderBy(o => o.id);
                    if (sections.Any() && sections.Count() > 1)
                    {
                        var temp = sections.TakeLast(2).Select(s => s.title);
                        data.mtitle = string.Join('-', temp);
                    }
                }

                response.Add(data);
            }

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

        /// <summary>
        /// 备件入库
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddEnterSparepart([FromBody]RequestSparepartInstock request)
        {
            if (request.spareparts == null || !request.spareparts.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var sp = _sparepartRepository.Get(q => q.id == request.sparepart_id && q.status == (int)RowState.Valid);
            if (sp == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var haveDuplicates = request.spareparts.GroupBy(i => i.code).Any(g => g.Count() > 1);
            if (haveDuplicates)
            {
                throw new BadRequestException(RequestEnum.SparepartCodeHasDuplicate);
            }

            foreach (var instock in request.spareparts)
            {
                var sps = _codeRepository.Get(q =>
                    q.sparepart_id == sp.id && q.sparepart_code == instock.code && q.status == (int)RowState.Valid);
                if (sps != null)
                {
                    throw new BadRequestException(RequestEnum.SparepartCodeHasExist);
                }
            }

            var count = request.spareparts.Count();
            var code = "R-1";
            var lastSku = count + sp.sku;

            var existRecord = _recordRepository
                .GetList(q => q.projectid == ProjectId && q.type == (int)StockCategory.InStock && q.status == (int)RowState.Valid)
                .OrderByDescending(m => m.id).FirstOrDefault();
            if (existRecord != null)
            {
                var trim = existRecord.record_code.Split('-');
                code = trim[0] + "-" + Convert.ToString(int.Parse(trim[1]) + 1);
            }

            var entity = new siger_project_sparepart_record
            {
                create_mid = UserId,
                create_time = UnixTimeHelper.GetNow(),
                projectid = ProjectId,
                IO_type = 1, //返修入库
                last_sku = lastSku,
                record_code = code,
                price = sp.price,
                sum_price = sp.price * lastSku,
                type = (int)StockCategory.InStock,
                number = request.spareparts.Count(),
                operate_mid = UserId.ToStr(),
                order_code = code,
                remark = "",
                sparepartid = request.sparepart_id,
            };
            _recordRepository.Insert(entity);

            //修改备件
            sp.sku = lastSku;
            _sparepartRepository.Update(sp);

            //添加备件代码
            foreach (var sparepart in request.spareparts)
            {
                var sparepartcode = new siger_project_sparepart_code
                {
                    sparepart_id = request.sparepart_id,
                    create_time = DateTime.Now,
                    creator_mid = UserId,
                    project_id = ProjectId,
                    repair_count = sparepart.repair_count,
                    record_code = code,
                    sparepart_code = sparepart.code,
                    status = (int)RowState.Valid
                };
                _codeRepository.Insert(sparepartcode);
            }

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

        /// <summary>
        /// 备件入库
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddEnterSparepart2([FromBody]RequestSparepartInstock2 request)
        {
            var sp = _sparepartRepository.Get(q =>
                q.id == request.sparepart_id && q.status == (int)RowState.Valid);
            if (sp == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var count = request.count;
            var code = "R-1";
            var lastSku = count + sp.sku;

            var existRecord = _recordRepository
                .GetList(q => q.projectid == ProjectId && q.type == (int)StockCategory.InStock && q.status == (int)RowState.Valid)
                .OrderByDescending(m => m.id).FirstOrDefault();
            if (existRecord != null)
            {
                var trim = existRecord.record_code.Split('-');
                code = trim[0] + "-" + Convert.ToString(int.Parse(trim[1]) + 1);
            }

            var entity = new siger_project_sparepart_record
            {
                create_mid = UserId,
                create_time = UnixTimeHelper.GetNow(),
                projectid = ProjectId,
                IO_type = request.io_type, //返修入库
                last_sku = lastSku,
                record_code = code,
                price = sp.price,
                sum_price = sp.price * lastSku,
                type = (int)StockCategory.InStock,
                number = request.count,
                operate_mid = UserId.ToStr(),
                order_code = code,
                remark = request.location,
                sparepartid = request.sparepart_id,
            };
            _recordRepository.Insert(entity);

            //修改备件
            sp.sku = lastSku;
            _sparepartRepository.Update(sp);

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

        /// <summary>
        /// 出库
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddcomeSparepart([FromBody]RequestAddEnterSparepart request)
        {
            var sp = _sparepartRepository.Get(q => q.id == request.sparepartid.ToInt() && q.status == (int)RowState.Valid);
            if (sp == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            if (request.number.ToInt() > sp.sku)
            {
                throw new ServerException(300060);
            }
            var code = "C-1";
            var lastSku = sp.sku - request.number.ToInt();

            var existRecord = _recordRepository
                .GetList(q => q.projectid == ProjectId && q.type == (int)StockCategory.OutStock && q.status == (int)RowState.Valid)
                .OrderByDescending(m => m.id).FirstOrDefault();
            if (existRecord != null)
            {
                var trim = existRecord.record_code.Split('-');
                if (trim.Length == 2)
                {
                    code = trim[0] + "-" + Convert.ToString(int.Parse(trim[1]) + 1);
                }
            }

            var entity = new siger_project_sparepart_record
            {
                create_mid = UserId,
                create_time = UnixTimeHelper.GetNow(),
                projectid = ProjectId,
                IO_type = request.IO_type.ToInt(),
                last_sku = lastSku,
                record_code = code,
                price = sp.price,
                sum_price = sp.price * lastSku,
                type = (int)StockCategory.OutStock,
                number = request.number.ToInt(),
                operate_mid = request.operate_mid,
                remark = request.remark.ToStr(),
                sparepartid = request.sparepartid.ToInt(),
                is_exchange = request.is_exchange.ToInt()
            };
            _recordRepository.Insert(entity);

            //修改备件
            sp.sku = lastSku;
            _sparepartRepository.Update(sp);

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

        [HttpPost]
        public IActionResult ExportSparepartRecord([FromBody]RequestSearchSparepartRecord request)
        {
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);

            var response = new List<ResponseGetSparepartRecord>();
            var startTime = 0;
            if (!string.IsNullOrWhiteSpace(request.startTime))
            {
                startTime = UnixTimeHelper.GetUnixByShortDate(request.startTime);
            }

            var endTime = 0;
            if (!string.IsNullOrWhiteSpace(request.endTime))
            {
                endTime = UnixTimeHelper.GetUnixByShortDate(request.endTime);
            }

            var machineIds = new List<int>();
            if (!string.IsNullOrWhiteSpace(request.machineIds))
            {
                foreach (var machineId in request.machineIds.Split(','))
                {
                    machineIds.Add(int.Parse(machineId));
                }
            }
            var list = _recordRepository.GetPagedList(startTime, endTime, request.keyword,
                request.s_is_standard, request.s_is_substitute, request.skutype.ToInt(), request.inStockType.ToInt(), request.outStockType.ToInt(),
                request.link, machineIds, request.sparepart.ToInt(), ProjectId, request.page, request.pagesize, true);
            if (!list.Data.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            foreach (var sparepartRecord in list.Data)
            {
                var data = Mapper<SparepartRecord, ResponseGetSparepartRecord>.Map(sparepartRecord);
                data.location = sparepartRecord.machineId != 0 ?
                    string.Join('-', _repairRepository.GetParentLevelSections(sparepartRecord.machineId, ProjectId))
                    : string.Empty;
                response.Add(data);
            }
            var temporaryFileName = $"sparepart_record_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<SparepartRecordList>();
            try
            {
                var repairList = new List<SparepartRecordList>();
                var isTranslate = _sparepartRepository.GetProjectLanguage(ProjectId) == (int)LanguageType.EN;
                foreach (var record in response)
                {
                    var entity = new SparepartRecordList
                    {
                        RecordCode = record.record_code,
                        Code = record.code,
                        Param=record.param,
                        Name = record.stitle,
                        CreateTime = UnixTimeHelper.ConvertStringDateTime(record.create_time.ToString())
                            .ToString(ParameterConstant.YearMonthDayHourMinute),
                        Creator = record.uname,
                        IOType = ConvertIOType(record.type, record.IO_type, isTranslate),
                        Location = record.location,
                        Number = record.number,
                        Price = record.price,
                        TotalPrice = record.sum_price,
                        OrderCode = record.order_code,
                        Operator = record.operate_name,
                        Sku = record.last_sku.ToString(),
                        Remark = record.remark,
                    };
                    repairList.Add(entity);
                }

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

        private string ConvertIOType(int type, int ioType, bool isTranslate)
        {
            switch (type)
            {
                case 1: //出库
                    if (isTranslate)
                    {
                        var outEnum_EN = (OutStockCategory_EN)Enum.Parse(typeof(OutStockCategory_EN), ioType.ToString());
                        return EnumHelper.GetEnumDesc(outEnum_EN);
                    }
                    var outEnum = (OutStockCategory)Enum.Parse(typeof(OutStockCategory), ioType.ToString());
                    return EnumHelper.GetEnumDesc(outEnum);
                case 2: //入库
                    if (isTranslate)
                    {
                        var inEnum_EN = (InStockCategory_EN)Enum.Parse(typeof(InStockCategory_EN), ioType.ToString());
                        return EnumHelper.GetEnumDesc(inEnum_EN);
                    }
                    var inEnum = (InStockCategory)Enum.Parse(typeof(InStockCategory), ioType.ToString());
                    return EnumHelper.GetEnumDesc(inEnum);
            }

            return string.Empty;
        }
    }
}