using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Filters;
using Siger.ApiCommon.Result;
using Siger.ApiCommon.Utilities;
using Siger.ApiQMS.Utility;
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.QmsRepository.Entities;
using Siger.Middlelayer.QmsRepository.Repositories.Interface;
using Siger.Middlelayer.QmsRepository.Request;
using Siger.Middlelayer.QmsRepository.Response;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Request;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.ApiQMS.Controllers
{
    public class BarcodeController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IQmsBarcodeGunSetRepository _barcodeGunSetRepository;
        private readonly IQmsBarcodeBatchRepository _barcodeBatchRepository;

        public BarcodeController(IUnitOfWork unitOfWork, IQmsBarcodeGunSetRepository barcodeGunSetRepository,
            IQmsBarcodeBatchRepository barcodeBatchRepository)
        {
            _unitOfWork = unitOfWork;
            _barcodeBatchRepository = barcodeBatchRepository;
            _barcodeGunSetRepository = barcodeGunSetRepository;
        }

        [HttpGet]
        public IActionResult GetSetList(int page = PageIndex, int pagesize = PageSize)
        {
            var response = _barcodeGunSetRepository.GetPagedList(page, pagesize, q => q.status == (int) RowState.Valid);
            return new PagedObjectResult(response.Data, response.Total, page, pagesize);
        }

        [HttpGet]
        public IActionResult GetStations()
        {
            var sets = _barcodeGunSetRepository.GetList(q => q.status == (int)RowState.Valid)
                .OrderBy(q => q.station_ip).Select(m => new
                {
                    m.id,
                    name = m.station_name
                }).ToList();
            return new ObjectResult(sets);
        }

        [HttpPost]
        public IActionResult Update([FromBody]RequestUpdateComment request)
        {
            var set = _barcodeGunSetRepository.GetList(q => q.status == (int) RowState.Valid)
                .OrderByDescending(q => q.create_time).FirstOrDefault();
            if (set == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            set.comment = request.comment ?? "";
            _barcodeGunSetRepository.Update(set);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult UpdateById([FromBody]RequestUpdateCommentById request)
        {
            var set = _barcodeGunSetRepository.Get(q => q.status == (int) RowState.Valid && q.id == request.id);
            if (set == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            set.comment = request.comment ?? "";
            _barcodeGunSetRepository.Update(set);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

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

            foreach (var requestId in request.ids)
            {
                var set = _barcodeGunSetRepository.Get(requestId);
                if (set != null)
                {
                    set.status = (int) RowState.Invalid;
                    _barcodeGunSetRepository.Update(set);
                }
            }
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [NoFilter]
        [NoTokenValidateFilter]
        [HttpPost]
        public IActionResult Save([FromBody]RequestSaveBarcode request)
        {
            if (string.IsNullOrWhiteSpace(request.mac))
            {
                throw new ClientException("Mac address is empty.");
            }
            if (string.IsNullOrWhiteSpace(request.holderIP))
            {
                throw new ClientException("Ip Address is empty.");
            }
            if (string.IsNullOrWhiteSpace(request.data))
            {
                throw new ClientException("No data.");
            }

            if (request.data == "SCANNERCONFIG\r") //保存扫码枪
            {
                return SaveGun(request);
            }
            return SaveData(request);
        }

        private IActionResult SaveGun(RequestSaveBarcode request)
        {
            var set = _barcodeGunSetRepository.Get(q => q.number == request.mac && q.status == (int) RowState.Valid);
            if (set != null)
            {
                set.create_time = DateTime.Now;
                _barcodeGunSetRepository.Update(set);
            }
            else
            {
                var gun = new siger_qms_barcodegun_set
                {
                    station_name = request.holderIP,
                    station_ip = request.holderIP,
                    create_time = DateTime.Now,
                    number = request.mac,
                    projectid = 0
                };
                _barcodeGunSetRepository.Insert(gun);
            }
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new ClientException("Save failed.");
        }

        private IActionResult SaveData(RequestSaveBarcode request)
        {
            var set = _barcodeGunSetRepository.Get(q => q.status == (int)RowState.Valid && q.number == request.mac);
            if (set == null)
            {
                throw new ClientException("Scanning gun has not been maintained.");
            }
            var barcode = new CheckSnHelper();
            barcode.SplitBarcode(request.data);
            if (barcode.campo4D.Length != 5)
            {
                throw new ClientException("Production Date is invalid.");
            }
            var data = new siger_qms_barcode_batch
            {
                barcodegun_id = set.id,
                barcode = request.data,
                part_number = barcode.campoP,
                quantity = barcode.campoQ.Replace("\u001e\u0004\r","").Trim().ToDouble(),
                acc_code = barcode.campoT,
                produce_time = DateTime.Parse("20"+ barcode.campo4D.Substring(0,2)+ "-1-1").AddDays(barcode.campo4D.Substring(2, 3).ToDouble()),
                duns = barcode.campo12V,
                feeding_time = DateTime.Now,
                supplier = barcode.campo13V,
                matrix = barcode.campo10S,
                heat = barcode.campo1T,
                steel_route = barcode.campo11S,
                projectid = 0
            };
            _barcodeBatchRepository.Insert(data);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new ClientException("Save failed.");
        }

        [HttpGet]
        public IActionResult GetBarcodeList(int stationid, string duns, string barcode, string starttime,
            string endtime, int page = PageSize, int pagesize = PageSize, int toexcel = 0)
        {
            var data = _barcodeBatchRepository.GetPagedList(stationid, duns, barcode, starttime, endtime, page,
                pagesize, toexcel);
            if (toexcel == 0)
            {
                return new PagedObjectResult(data.Data, data.Total, page, pagesize);
            }

            return ExportBarcodes(data.Data);
        }

        private IActionResult ExportBarcodes(IEnumerable<RespoonseBarcodeBatch> data)
        {
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            if (!data.Any())
            {
                throw new BadRequestException(RequestEnum.UserNotFound);
            }
            var temporaryFileName = $"barcode_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<BarcodeList>();
            try
            {
                var userList = new List<BarcodeList>();
                var index = 1;
                foreach (var barcode in data)
                {
                    var user = new BarcodeList
                    {
                        No = index,
                        AccCode = barcode.acc_code,
                        Barcode = barcode.barcode,
                        CreateTime = barcode.feeding_time_str,
                        Duns = barcode.duns,
                        Heat = barcode.heat,
                        Matrix = barcode.matrix,
                        PartNumber = barcode.part_number,
                        ProductionDate = barcode.produce_time_str,
                        Quanlity = barcode.quantity.ToStr(),
                        Supplier = barcode.supplier,
                        StationName = barcode.station_name,
                        SteelRoute = barcode.steel_route
                    };
                    userList.Add(user);

                    index++;
                }

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

        [HttpGet]
        public IActionResult GetSuppliers()
        {
            var sets = _barcodeBatchRepository.GetList(q => q.status == (int)RowState.Valid)
                .OrderBy(q => q.duns).Select(m => new
                {
                    m.id,
                    name = m.duns
                }).ToList();
            return new ObjectResult(sets);
        }

        [HttpGet]
        public IActionResult GetBarcodes(string keyword, int count = 50)
        {
            var sets = _barcodeBatchRepository.GetList(q => q.status == (int)RowState.Valid && (string.IsNullOrWhiteSpace(keyword) || q.barcode.Contains(keyword)))
                .Take(count).OrderBy(q => q.barcode).Select(m => new
                {
                    m.id,
                    name = m.barcode
                }).ToList();
            return new ObjectResult(sets);
        }

        [HttpPost]
        public IActionResult CreateDataMatrix([FromBody]RequestCreateDataMatrix request)
        {
            const string rs = "\u001E";
            const string gs = "\u001D";
            const string eot = "\u0004";
            var code = new StringBuilder();
            var date = request.date.ToDateTime();
            var year = date.Year.ToStr().Substring(2, 2);

            code.AppendFormat("[)>{0}06{1}", rs, gs);
            code.AppendFormat("P{0}{1}", request.partname, gs);
            code.AppendFormat("12V{0}{1}", request.supplierduns, gs);
            code.AppendFormat("T{0}{1}", request.traceability, gs);
            code.AppendFormat("Q{0}{1}", request.quantity, gs);
            code.AppendFormat("4D{0}{1}", year + DateTime.Parse(request.date).DayOfYear.ToString("#000"), gs);
            code.AppendFormat("10S{0}{1}", request.matrix, gs);
            code.AppendFormat("13V{0}{1}", request.steelduns, gs);
            code.AppendFormat("11S{0}{1}", request.steelroute, gs);
            code.AppendFormat("{0}{1}", rs, eot);

            return new ObjectResult(code.ToString());
        }
    }

}