using Hotline.Caching.Interfaces;
using Hotline.DI;
using Hotline.Settings.TimeLimitDomain.Repository;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos.Settings;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Tools;
using Mapster;
using MapsterMapper;
using Microsoft.Extensions.Logging;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Settings.TimeLimitDomain;

/// <summary>
/// 自贡过期时间计算
/// </summary>
[Injection(AppScopes = EAppScope.ZiGong)]
public class ZiGongExpireTimeLimit : ExpireTimeLimitBase, ICalcExpireTime, IScopeDependency
{
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly ITimeLimitSettingRepository _timeLimitSettingRepository;
    private readonly ITimeLimitSettingInventoryRepository _timeLimitSettingInventoryRepository;
    private readonly ITimeLimitSettingAttributeRepository _timeLimitSettingAttributeRepository;
    private readonly IExpireTimeHandler _expireTimeHandler;
    private readonly IMapper _mapper;
    private readonly IRepository<SystemSetting> _systemSettingRepository;
    private readonly ILogger<ZiGongExpireTimeLimit> _logger;
    private readonly IDaySettingCacheManager _daySettingCacheManager;

    public ZiGongExpireTimeLimit(ISystemSettingCacheManager systemSettingCacheManager, ITimeLimitSettingRepository timeLimitSettingRepository, IExpireTimeHandler expireTimeHandler, IMapper mapper, IRepository<SystemSetting> systemSettingRepository, IDaySettingCacheManager daySettingCacheManager, ITimeLimitSettingAttributeRepository timeLimitSettingAttributeRepository, ITimeLimitSettingInventoryRepository timeLimitSettingInventoryRepository, ILogger<ZiGongExpireTimeLimit> logger) : base(systemSettingCacheManager, timeLimitSettingRepository, expireTimeHandler, mapper, daySettingCacheManager)
    {
        _systemSettingCacheManager = systemSettingCacheManager;
        _timeLimitSettingRepository = timeLimitSettingRepository;
        _expireTimeHandler = expireTimeHandler;
        _mapper = mapper;
        _systemSettingRepository = systemSettingRepository;
        _daySettingCacheManager = daySettingCacheManager;
        _timeLimitSettingAttributeRepository = timeLimitSettingAttributeRepository;
        _timeLimitSettingInventoryRepository = timeLimitSettingInventoryRepository;
        _logger = logger;
    }

    //public override async Task<ExpiredTimeWithConfig> CalcExpiredTime(DateTime beginTime, EFlowDirection flowDirection, OrderTimeClacInfo order)
    //{
    //    order.FlowDirection = flowDirection;
    //    if (EFlowDirection.CenterToOrg == flowDirection || EFlowDirection.CenterToCenter == flowDirection)
    //    {
    //        var timeConfig = await GetTimeConfigByOrderAsync(order);
    //        if (order.FlowDirection == EFlowDirection.CenterToCenter)
    //            _logger.LogInformation($"中心到中心的订单:{timeConfig.ToJson()}");
    //        timeConfig.WorkTime = GetWorkTimes(SettingConstants.WorkTime);
    //        var result = await _expireTimeHandler.CalcEndTimeAsync(beginTime, timeConfig);

    //        var expiredTimeWithConfig = timeConfig.Adapt<ExpiredTimeWithConfig>();
    //        return result.Adapt(expiredTimeWithConfig);
    //    }

    //    return await base.CalcExpiredTime(beginTime, flowDirection, order);
    //}

    public override async Task<ExpiredTimeWithConfig> CalcExpiredTime(DateTime beginTime,DateTime startTime,EFlowDirection flowDirection,OrderTimeClacInfo order)
    {
        order.FlowDirection = flowDirection;
        if (EFlowDirection.CenterToOrg == flowDirection || EFlowDirection.CenterToCenter == flowDirection)
        {
            var timeConfig = await GetTimeConfigByOrderAsync(order);
            if (order.FlowDirection == EFlowDirection.CenterToCenter)
                _logger.LogInformation($"中心到中心的订单:{timeConfig.ToJson()}");
            timeConfig.WorkTime = GetWorkTimes(SettingConstants.WorkTime);
            var result = await _expireTimeHandler.CalcEndTimeAsync(beginTime, startTime, timeConfig);

            var expiredTimeWithConfig = timeConfig.Adapt<ExpiredTimeWithConfig>();
            return result.Adapt(expiredTimeWithConfig);
        }

        return await base.CalcExpiredTime(beginTime,startTime, flowDirection, order);
    }

    public override TimeConfig GetOrderTimeLimitConfig(string? code = null)
    {
        return GetTimeConfigByOrderAsync(new OrderTimeClacInfo(code)).GetAwaiter().GetResult();
    }

    /// <summary>
    /// 根据订单信息获取时间配置
    /// </summary>
    /// <param name="orderInfo"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    private async Task<TimeConfig> GetTimeConfigByOrderAsync(OrderTimeClacInfo orderInfo)
    {
        var busCode = string.Empty;
        var code = string.Empty;
        orderInfo.ForeachClassProperties(async (order, property, name, value) =>
        {
            if (value is null) return true;
            if (name == OrderTimeClacInfo.BusCodeName)
            {
                busCode = value.ToString();
                return true;
            }
            TimeLimitSettingAttribute? timeLimitAttribute = null;
            var query = _timeLimitSettingAttributeRepository.Queryable();
            var realValue = string.Empty;
            if (value is Boolean)
            {
                if ((bool)value == false) return true;
                realValue = "true";
            }
            else if (value is String || value is Enum)
            {
                if (value is null) return true;
                realValue = value.ToString()!;
            }
            query = query.Where(m => m.Name == name);
            if (property.HasAttribute<IsFuzzyQueryAttribute>())
                query = query.Where(m => realValue.Contains(m.Value));
            else
                query = query.Where(m => m.Value == realValue);

            var noBusCodeAttribute = await query.FirstAsync(m => m.BusCode == "");
            if (false == property.HasAttribute<NoCodeAttribute>())
                query = query.Where(m => m.BusCode == busCode);
            timeLimitAttribute = await query.FirstAsync();
            timeLimitAttribute ??= noBusCodeAttribute;
            if (timeLimitAttribute is null) return true;
            code += timeLimitAttribute.Code;
            if (timeLimitAttribute.IsCommon == false)
                return false;
            return true;
        });
        if (busCode.IsNullOrEmpty() && code.IsNullOrEmpty()) return GetOrderTimeLimitConfigBase();
        var inventory = await _timeLimitSettingInventoryRepository.GetByCode(code);
        if (inventory is not null) return inventory.Adapt<TimeConfig>();
        var timeConfig = await _timeLimitSettingRepository.GetByBusCode(busCode)
            ?? throw new UserFriendlyException($"缺少busCode:{busCode}, 的time_limit_setting 设置;");
        return timeConfig.Adapt<TimeConfig>();
    }
}

