using AutoMapper;
using Kean.Domain.Stock.Commands;
using Kean.Domain.Stock.Events;
using Kean.Domain.Stock.Repositories;
using Kean.Domain.Stock.SharedServices.Proxies;
using Kean.Infrastructure.Configuration;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Kean.Domain.Stock.CommandHandlers
{
    /// <summary>
    /// 更新命令处理程序
    /// </summary>
    public sealed class UpdateCommandHandler : CommandHandler<UpdateCommand>
    {
        private readonly ICommandBus _commandBus; // 命令总线
        private readonly INotification _notifications; // 总线通知
        private readonly IMapper _mapper; // 模型映射
        private readonly IStockRepository _stockRepository; // 存储仓库
        private readonly IWarehouseRepository _warehouseRepository; // 库房仓库
        private readonly BarcodeValidator _barcodeValidator; // 条码验证器
        private readonly TaskProxy _taskProxy; // 任务域

        /// <summary>
        /// 依赖注入
        /// </summary>
        public UpdateCommandHandler(
            ICommandBus commandBus,
            INotification notifications,
            IMapper mapper,
            IStockRepository stockRepository,
            IWarehouseRepository warehouseRepository,
            BarcodeValidator barcodeValidator,
            TaskProxy taskProxy)
        {
            _commandBus = commandBus;
            _notifications = notifications;
            _mapper = mapper;
            _stockRepository = stockRepository;
            _warehouseRepository = warehouseRepository;
            _barcodeValidator = barcodeValidator;
            _taskProxy = taskProxy;
        }

        /// <summary>
        /// 处理程序
        /// </summary>
        public override async Task Handle(UpdateCommand command, CancellationToken cancellationToken)
        {
            if (command.ValidationResult.IsValid)
            {
                // 条码格式校验
                if (!await _barcodeValidator.Validate(command.Barcode))
                {
                    await _commandBus.Notify(nameof(command.Barcode), "条码格式不正确", command.Barcode,
                            cancellationToken: cancellationToken);
                    return;
                }
                var original = await _stockRepository.GetCell(command.Barcode);
                // 托盘不存在
                if (!original.HasValue)
                {
                    await _commandBus.Notify(nameof(command.Barcode), "托盘不存在", command.Barcode,
                            cancellationToken: cancellationToken);
                    return;
                }
                if (command.Tag.Contains("SetRollResult"))
                {
                }
                else
                {
                    // 托盘有任务
                    if (await _taskProxy.HasTask(command.Barcode))
                    {
                        await _commandBus.Notify(nameof(command.Barcode), "托盘有任务", command.Barcode,
                            cancellationToken: cancellationToken);
                        return;
                    }
                }

                // 时间戳
                command.Timestamp ??= DateTime.Now;
                // 切点事件
                var event0 = _mapper.Map<UpdateExecutingEvent>(command);
                event0.Cell = original.Value;
                await _commandBus.Trigger(event0, cancellationToken);
                if (!_notifications.Any())
                {
                    // 允许删除库存
                    var stock = _mapper.Map<Models.Stock>(command);
                    stock.Cell = original.Value;
                    stock.Timestamp = command.Timestamp.Value;
                    if (await _stockRepository.UpdateStock(stock).ContinueWith(task =>
                    {
                        if (task.Exception?.InnerException is RepositoryException ex)
                        {
                            task.Exception.Handle(_ => true);
                            _commandBus.Notify(ex.Member.Key, ex.Message, ex.Member.Value,
                                cancellationToken: cancellationToken).Wait();
                            return true;
                        }
                        return false;
                    }))
                    {
                        return;
                    }
                    // 有效行
                    stock.Lines = stock.Lines.Where(l => l.Id > 0).ToArray();
                    if (stock.Lines.Any())
                    {
                        // 成功事件
                        var event1 = _mapper.Map<UpdateSuccessEvent>(command);
                        event1.Cell = stock.Cell;
                        event1.Timestamp = command.Timestamp.Value;
                        await _commandBus.Trigger(event1, cancellationToken);
                    }
                }
            }
            else
            {
                await _commandBus.Notify(command.ValidationResult,
                    cancellationToken: cancellationToken);
            }
        }
    }
}