using AutoMapper;
using Kean.Application.Command.Interfaces;
using Kean.Application.Command.ViewModels;
using Kean.Domain.Stock.Commands;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Orleans;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Kean.Application.Command.Implements
{
    /// <summary>
    /// 库存命令服务实现
    /// </summary>
    public class StockService : IStockService
    {
        private readonly ILogger<StockService> _logger; // 日志
        //private readonly ICommandBus _bus; // 命令总线
        //private readonly INotification _notifications; // 总线通知
        private readonly IMapper _mapper; // 模型映射
        private readonly IClusterClient _cluster; // 筒仓客户端

        /// <summary>
        /// 依赖注入
        /// </summary>
        public StockService(
            ILogger<StockService> logger,
            //ICommandBus bus,
            //INotification notifications,
            IMapper mapper,
            IClusterClient cluster)
        {
            _logger = logger;
            //_bus = bus;
            //_notifications = notifications;
            _mapper = mapper;
            _cluster = cluster;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.Inbound 方法
         */
        public async Task<Failure> Inbound(Stock stock, bool? full, int? destination)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<InboundCommand>(stock);
            command.Destination = destination;
            command.Full = full;
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:入库:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).Inbound(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.Outbound 方法
         */
        public async Task<Failure> Outbound(Stock stock)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<OutboundCommand>(stock);
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:出库:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).Outbound(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.Update 方法
         */
        public async Task<Failure> Update(Stock stock)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<UpdateCommand>(stock);
            command.Transaction = "Update";
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:更新:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).Update(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.Combine 方法
         */
        public async Task<Failure> Combine(Stock stock, bool? full, int? destination)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<CombineCommand>(stock);
            command.Destination = destination;
            command.Full = full;
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:合并:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).Combine(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.Inventory 方法
         */
        public async Task<Failure> Inventory(Stock stock)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<InventoryCommand>(stock);
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:盘点:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).Inventory(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        ///////////////////////////////////////////
        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.ScanInbound 方法
         */
        public async Task<(string Device, Failure Failure)> ScanInbound(Stock stock, bool? full, int? destination)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<ScanInboundCommand>(stock);
            command.Destination = destination;
            command.Full = full;
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:扫描入库:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).ScanInbound(command);
            //
            if (result.Failure != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.PalletIn 方法
         */
        public async Task<Failure> PalletIn(Stock stock, bool? full, int? destination)
        {
            var stopwatch = new Stopwatch();
            var command = _mapper.Map<PalletInCommand>(stock);
            command.Destination = destination;
            command.Full = full;
            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:托盘入库:条码[{Barcode}],标签[{Tag}]。", hash, stock.Barcode, stock.Tag);
            stopwatch.Start();
            //await _bus.Execute(command);
            //var result = _notifications.FirstOrDefault();
            var result = await _cluster.GetGrain<IAggregateGrain>(Guid.Empty).PalletIn(command);
            //
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。", hash, stopwatch.ElapsedMilliseconds);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.AgvApplyIn 方法
         */
        public async Task<(string Device, Failure Failure)> AgvApplyIn(
            string requestNo,
            string barcode,
            string postUser,
            string targetNo,
            IEnumerable<Batch> batchs)
        {
            (string Device, Failure Failure) result;
            Failure failure = new Failure();
            result.Failure = failure;
            result.Device = string.Empty;

            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            PreScanInboundCommand command = new PreScanInboundCommand();

            command.RequestNo = requestNo;
            command.Barcode = barcode;

            //@=@ W1固定值 300000-数据接收缓存区
            command.Source = "300000";
            command.Postuser = postUser;
            command.Operator = -4;
            command.Batchs = _mapper.Map<IEnumerable<Kean.Domain.Stock.Models.Batch>>(batchs);

            //输送
            if (!targetNo.Equals("ASRS"))
            {
                string transaction = "bypass";
                int bypassArea = 0;
                //@=@ W1固定值 targetNo转换bypassArea
                switch (targetNo)
                {
                    case "L1-1":
                        bypassArea = 150001;
                        break;
                    case "L1-2":
                        bypassArea = 150002;
                        break;
                    case "L2-1":
                        bypassArea = 160001;
                        break;
                    case "L2-2":
                        bypassArea = 160002;
                        break;
                    case "L3-1":
                        bypassArea = 170001;
                        break;
                    case "L3-2":
                        bypassArea = 170002;
                        break;
                    case "L4-1":
                        bypassArea = 250001;
                        break;
                    case "L4-2":
                        bypassArea = 250002;
                        break;
                    case "L5-1":
                        bypassArea = 260001;
                        break;
                    case "L5-2":
                        bypassArea = 260002;
                        break;
                    case "L6-1":
                        bypassArea = 270001;
                        break;
                    case "L6-2":
                        bypassArea = 270002;
                        break;
                    case "BException":
                        bypassArea = 120000;
                        break;
                    case "AException":
                        bypassArea = 220000;
                        break;
                    default:
                        result.Failure.ErrorMessage = $"目标地址({targetNo})不正确,请检查";
                        return result;
                }
               
                command.Tag = JsonConvert.SerializeObject(new
                {
                    Transaction = transaction,
                    postUser = postUser,
                    BypassArea  = bypassArea
                });
            }

            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:AgvApplyIn参数-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                requestNo = requestNo,
                barcode = barcode,
                postUser = postUser,
                targetNo = targetNo,
                batchs = batchs
            }));

            stopwatch.Start();
            result = await grain.PreScanInbound(command);
            if (result.Failure != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);

            
            return result;
        }

        /*
        * 实现 Kean.Application.Command.Interfaces.IStockService.SetRollResult 方法
        */
        public async Task<Failure> SetRollResult(
            string batchNo,
            string code,
            string message,
            int @operator)
        {
            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            SetRollResultCommand command = new SetRollResultCommand();
            command.BatchNo = batchNo;
            command.Code = code;
            command.Message = message;
            command.Operator = @operator;

            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:SetRollResult参数-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                batchNo = batchNo,
                code = code,
                message = message,
                @operator = @operator
            }));

            stopwatch.Start();
            var result = await grain.SetRollResult(command);

            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);
            return result;
        }
        /*
        * 实现 Kean.Application.Command.Interfaces.IStockService.ScanInbound 方法
        */
        public async Task<(string Device, Failure Failure)> ApplyIn(Stock stock, bool? full, int? destination)
        {
            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            PreScanInboundCommand command = new PreScanInboundCommand();
            //command.RequestNo = requestNo;
            command.Barcode = stock.Barcode;
            command.Sfc = stock.Lines.Select(r=>r.Bill ).ToArray();

            //@=@ 固定值
            string source = "110000";
            if (stock.Barcode.StartsWith("M2A"))
            {
                source = "210000";
            }
            if (stock.Barcode.StartsWith("W1JPA"))
            {
                source = "210000";
            }
            command.Source = source;
            command.Postuser = stock.Lines.First().Postuser;
            command.Operator = stock.Operator;
            command.Remark = stock.Lines.First().Remark;
            command.Qc = stock.Lines.First().QualityState;
            command.Tag = stock.Tag;

            command.AgvApplyInFlag = false;


            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:ApplyIn参数-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                barcode = command.Barcode,
                sfc = command.Sfc,
                slSource = command.Source,
                @operator = command.Operator
            }));

            stopwatch.Start();
            var result = await grain.PreScanInbound(command);

            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.FreezeThaw 方法
         */
        public async Task<(int barcodeCount, Failure Failure)> SetQcStatus(int @operator,
            string operation,
            int? code,
            string batch,
            DateTime? mfgFrom,
            DateTime? mfgTo,
            DateTime? inboundTimeFrom,
            DateTime? inboundTimeTo,
            string barcode,
            string supplier,
            string[] barcodes)
        {
            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            PreSetQcStatusCommand command = new PreSetQcStatusCommand();
            command.Enable = operation.Equals("freeze") ? false : true;
            command.Operator = @operator;
            command.GoodsCode = code;
            command.Batch = batch;
            command.ManufacturingDateFrom = mfgFrom;
            command.ManufacturingDateTo = mfgTo;
            command.InboundTimeFrom = inboundTimeFrom;
            command.InboundTimeTo = inboundTimeTo;
            command.Barcode = barcode;
            command.Supplier = supplier;
            command.Operator = @operator;
            command.BarcodeList = barcodes;

            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:SetQcStatus参数-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                @operator = @operator,
                operation = operation,
                code = code,
                batch = batch,
                mfgFrom = mfgFrom,
                mfgTo = mfgTo,
                inboundTimeFrom = inboundTimeFrom,
                inboundTimeTo = inboundTimeTo,
                barcode = barcode,
                supplier = supplier
            }));

            stopwatch.Start();
            var result = await grain.PreSetQcStatus(command);
            if (result.Failure != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);
            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.ChangeStorageProperty 方法
         */
        public async Task<Failure> ChangeStorageProperty(
            string requestNo,
            Batch batch,
            string freezenStatus)
        {
            Failure result = new Failure();
            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            ChangeStoragePropertyCommand command = new ChangeStoragePropertyCommand();

            command.RequestNo = requestNo;
            command.Serialno = batch.serialno;
            command.FreezenStatus = freezenStatus;
            command.Batch = _mapper.Map<Kean.Domain.Stock.Models.Batch>(batch);

            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:ChangeStorageProperty-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                requestNo = requestNo,
                freezenStatus = freezenStatus,
                batch = JsonConvert.SerializeObject(batch)
            }));

            stopwatch.Start();
            result = await grain.ChangeStorageProperty(command);
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);


            return result;
        }

        /*
         * 实现 Kean.Application.Command.Interfaces.IStockService.BatchReFeedback 方法
         */
        public async Task<Failure> BatchReFeedback(int[] id)
        {
            Failure result = new Failure();
            var stopwatch = new Stopwatch();
            var grain = _cluster.GetGrain<IAggregateGrain>(Guid.Empty);

            BatchReFeedbackCommand command = new BatchReFeedbackCommand();

            command.idList = id;

            var hash = command.GetHashCode();
            _logger.LogInformation("过程[{Hash}]开始:BatchReFeedback-{1}]。", hash, JsonConvert.SerializeObject(new
            {
                idList = string.Join(",", id)
            }));

            stopwatch.Start();
            result = await grain.BatchReFeedback(command);
            if (result != null)
            {
                _logger.LogWarning("过程[{Hash}]中断:{Failure}。", hash, result);
            }
            _logger.LogInformation("过程[{Hash}]结束:耗时{TimeSpan}ms。结果{Failure}", hash, stopwatch.ElapsedMilliseconds, result);


            return result;
        }

    }
}