using AutoMapper;
using Kean.Domain.Stock.Repositories;
using Kean.Domain.Task.Commands;
using Kean.Domain.Task.Enums;
using Kean.Domain.Task.Events;
using Kean.Domain.Task.Models;
using Kean.Domain.Task.Repositories;
using Kean.Domain.Task.SharedServices.Proxies;
using Kean.Infrastructure.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Threading;

namespace Kean.Domain.Task.CommandHandlers
{
    /// <summary>
    /// 创建输送命令处理程序
    /// </summary>
    public sealed class BypassEmptyCommandHandler : CommandHandler<BypassEmptyCommand>
    {
        private readonly ICommandBus _commandBus; // 命令总线
        private readonly INotification _notifications; // 总线通知
        private readonly IMapper _mapper; // 模型映射
        private readonly ITaskRepository _taskRepository; // 任务仓库
        private readonly Kean.Domain.Task.Repositories.IWarehouseRepository _warehouseRepository; // 库房仓库
        private readonly BarcodeInterpreter _barcodeInterpreter; // 条码解释器
        private readonly BarcodeValidator _barcodeValidator; // 条码验证器
        private readonly StockProxy _stockProxy; // 仓储域代理
        private readonly MaterialProxy _materialProxy;

        /// <summary>
        /// 依赖注入
        /// </summary>
        public BypassEmptyCommandHandler(
            ICommandBus commandBus,
            INotification notifications,
            IMapper mapper,
            ITaskRepository taskRepository,
            Kean.Domain.Task.Repositories.IWarehouseRepository warehouseRepository,
            BarcodeInterpreter barcodeInterpreter,
            BarcodeValidator barcodeValidator,
            StockProxy stockProxy,
            MaterialProxy materialProxy)
        {
            _commandBus = commandBus;
            _notifications = notifications;
            _mapper = mapper;
            _taskRepository = taskRepository;
            _warehouseRepository = warehouseRepository;
            _barcodeInterpreter = barcodeInterpreter;
            _barcodeValidator = barcodeValidator;
            _stockProxy = stockProxy;
            _materialProxy = materialProxy;
        }

        /// <summary>
        /// 处理程序
        /// </summary>
        public override async System.Threading.Tasks.Task Handle(BypassEmptyCommand command, CancellationToken cancellationToken)
        {
            if (command.ValidationResult.IsValid)
            {
                // 条码格式校验
                if (!await _barcodeValidator.Validate(command.Barcode))
                {
                    await _commandBus.Notify(nameof(command.Barcode), "条码格式不正确", command.Barcode,
                            cancellationToken: cancellationToken);
                    return;
                }
                // 任务重复
                if (await _taskRepository.HasTask(command.Barcode))
                {
                    await _commandBus.Notify(nameof(command.Barcode), "托盘正在执行任务", command.Barcode,
                            cancellationToken: cancellationToken);
                    return;
                }

                var pallet = await _barcodeInterpreter.Interpret(command.Barcode);
                // 不允许操作立库中的库存
                var cell = await _stockProxy.GetCell(command.Barcode);
                if (cell.HasValue && await _warehouseRepository.IsCell(cell.Value) == true)
                {
                    await _commandBus.Notify(nameof(command.Barcode), "不允许操作立库中的库存", command.Barcode,
                            cancellationToken: cancellationToken);
                    return;
                }

                // 获取操作位置
                var original = command.Original switch
                {
                    int i => await _warehouseRepository.GetStationById(i),
                    long i => await _warehouseRepository.GetStationById((int)i),
                    string s when s.StartsWith("name:") => await _warehouseRepository.GetStationByName(s[5..], command.Warehouse),
                    string s when s.StartsWith("device:") => await _warehouseRepository.GetStationByDevice(s[7..], command.Warehouse),
                    Station s => s,
                    _ => null
                };
                // 操作位置可用性
                if (original.AllowIn != true
                    || original.Pallet?.Contains(pallet) == false
                    || original.Spec?.Adaptive(command.Spec) == false)
                {
                    await _commandBus.Notify(nameof(command.Original), "操作位置不正确", command.Original,
                            cancellationToken: cancellationToken);
                    return;
                }
                //校验 托盘规则与申请位置是否匹配
                if ((original.Device.StartsWith("1") || original.Device.StartsWith("2")) && original.Device != "12226" && original.Device != "22226")
                {
                    Models.Warehouse warehouse = await _warehouseRepository.GetWarehouse(original.Warehouse);
                    if (warehouse.Code != command.Barcode.Substring(0, 3))
                    {
                        await _commandBus.Notify(nameof(command.Barcode), $"托盘({command.Barcode})不能进入({warehouse.Name})库房", command.Barcode,
                            cancellationToken: cancellationToken);
                        return;
                    }
                }

                if (!(await _stockProxy.GetCell(command.Barcode)).HasValue)
                {
                    int? endDevice = original?.Id;
                    var sGoods = await _materialProxy.GetMaterial(null, (string)pallet, true);
                    Models.Material goods = JsonConvert.DeserializeObject<Models.Material>(sGoods);
                    if (goods == null)
                    {
                        await _commandBus.Notify(nameof(command.Original), "空托盘条码解析类型失败", command.Original,
                            cancellationToken: cancellationToken);
                        return;
                    }

                    int? goodsid = goods.Id;

                    //@=@ W1固定值
                    int tempBypassArea = 110000;
                    if (command.Barcode.Substring(0, 5) == "W1JPB" || command.Barcode.Substring(0, 3) == "M2C")
                    {
                        tempBypassArea = 110000;
                    }
                    else
                    {
                        tempBypassArea = 210000;
                    }

                    command.Tag = JsonConvert.SerializeObject(new
                    {
                        isAgv = "1",
                        BypassArea = tempBypassArea,
                        postUser = "系统",
                        slTarget=""
                    });
                    command.Operator = -1;

                    await _stockProxy.PalletIn(
                        command.Barcode,
                        endDevice.Value,
                        goodsid.Value,
                        command.Operator,
                        command.Tag
                        );
                }
                else
                {
                    int? material = await _stockProxy.GetStorageMaterial(command.Barcode);

                    bool bPallet = await _taskRepository.IsPallet(material.Value);

                    if (bPallet)
                    {
                    }
                    else
                    {
                        await _commandBus.Notify(nameof(command.Barcode), $"托盘({command.Barcode})已经有库存,无法空托盘入库", command.Barcode,
cancellationToken: cancellationToken);
                        return;
                    }

                }



                //获取库存信息
                string bypassTag = await _taskRepository.GetBypassTag(command.Barcode);

                string isAgv = string.Empty;
                string slTarget = string.Empty;
                int bypassArea = 0;
                string postUser = string.Empty;
                string Transaction = "Bypass";
                int Operator = command.Operator;

                if (!string.IsNullOrEmpty(bypassTag))
                {
                    command.Tag = bypassTag;
                    JObject jObj = JObject.Parse(bypassTag);

                    JToken isAgvFlg = jObj.SelectToken("isAgv");
                    if (isAgvFlg != null)
                    {
                        isAgv = jObj["isAgv"].ToString();
                    }
                    JToken slTargetFlg = jObj.SelectToken("slTarget");
                    if (slTargetFlg != null)
                    {
                        slTarget = jObj["slTarget"].ToString();
                    }
                    JToken bypassAreaFlg = jObj.SelectToken("BypassArea");
                    if (bypassAreaFlg != null)
                    {
                        bypassArea = Convert.ToInt32(jObj["BypassArea"]);
                    }
                    JToken postUserFlg = jObj.SelectToken("postUser");
                    if (postUserFlg != null)
                    {
                        postUser = jObj["postUser"].ToString();
                    }
                }

                if (bypassArea == 0)
                {
                    //@=@ W1固定值
                    bypassArea = 110000;
                    if (command.Barcode.Substring(0, 5) == "W1JPB" || command.Barcode.Substring(0, 3) == "M2C")
                    {
                        bypassArea = 110000;
                    }
                    else
                    {
                        bypassArea = 210000;
                    }

                    command.Operator = -1;
                }
                // 获取目标位置
                var destinationCache = await _warehouseRepository.GetCacheByArea(bypassArea);
                if (destinationCache == null)
                {
                    await _commandBus.Notify("Destination", $"输送终点区域未知({bypassArea})", bypassArea,
cancellationToken: cancellationToken);
                    return;
                }

                var destination = destinationCache;
                //转换为实际出库站台
                if (destinationCache.Group == "Trans")
                {
                    destination = await _warehouseRepository.GetBypassStationByCell(original.Id, destinationCache.Area, command.Barcode.Substring(0,5));
                    if (destination == null)
                    {
                        await _commandBus.Notify(nameof(command.Destination), "未找到输送站台", command.Destination,
                            cancellationToken: cancellationToken);
                        return;
                    }
                }

                command.Original = original.Id;
                command.Destination = destination.Id;

                // 时间戳
                command.Timestamp ??= DateTime.Now;
                // 切点事件
                var event0 = _mapper.Map<BypassEmptyExecutingEvent>(command);
                event0.Original = original;
                event0.Destination = destination;
                await _commandBus.Trigger(event0, cancellationToken);
                if (!_notifications.Any())
                {
                    // 创建任务
                    var task = _mapper.Map<Models.Task>(command);
                    task.Type = TaskType.Bypass;
                    Output(nameof(command.Id), await _taskRepository.CreateTask(task));
                    // 成功事件
                    var event1 = _mapper.Map<BypassEmptySuccessEvent>(command);
                    event1.Original = original;
                    event1.Destination = destination;
                    await _commandBus.Trigger(event1, cancellationToken);
                    // 手动
                    if (command.Manual && !_notifications.Any())
                    {
                        await _commandBus.Execute(new CompleteCommand { Id = command.Id }, cancellationToken);
                    }
                }
            }
            else
            {
                await _commandBus.Notify(command.ValidationResult,
                    cancellationToken: cancellationToken);
            }
        }
    }
}