using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Models.Settings;
using QYZH.InteractiveMagazine.Repository;
using SqlSugar;

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// 勋章服务实现
/// </summary>
public class MedalService(BaseRepository<Medal> medalRepository, IOptions<MedalRuleConfigSettings> medalRuleConfig, ILogger<MedalService> logger) : BaseRepository<Medal>, IMedalService
{

    /// <summary>
    /// 创建勋章（含规则，事务）
    /// </summary>
    public async Task<MedalOutput> CreateAsync(MedalInput input)
    {
        logger.LogInformation("正在创建勋章，勋章名称: {Name}", input.Name);

        if (string.IsNullOrWhiteSpace(input.Name))
        {
            throw new BusinessException("勋章名称不能为空", ResultCode.BAD_REQUEST);
        }

        if (string.IsNullOrWhiteSpace(input.Type))
        {
            throw new BusinessException("勋章类型不能为空", ResultCode.BAD_REQUEST);
        }

        var medal = new Medal
        {
            Name = input.Name.Trim(),
            Description = input.Description,
            ImageUrl = input.ImageUrl,
            SortOrder = input.SortOrder,
            Type = Enum.Parse<MedalTypeEnum>(input.Type, true),
            JournalId = input.JournalId,
            Status = (int)DefaultStatusEnum.Active,
            CreatedBy = "System",
            UpdatedBy = "System",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now,
            IsDeleted = false
        };

        try
        {
            await UseTranAsync(async () =>
            {
                var result = await medalRepository.InsertAsync(medal);
                if (!result)
                {
                    throw new BusinessException("创建勋章失败", ResultCode.GLOBAL_ERROR);
                }

                if (input.Rules != null && input.Rules.Count > 0)
                {
                    await InsertRulesAsync(medal.Id, input.Rules);
                }
            });
        }
        catch (BusinessException)
        {
            throw;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "勋章创建事务失败，勋章名称: {Name}", input.Name);
            throw new BusinessException("创建勋章失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("勋章创建成功，勋章名称: {Name}, ID: {Id}", input.Name, medal.Id);

        var rules = await GetRulesByMedalIdAsync(medal.Id);
        return BuildMedalOutput(medal, rules);
    }

    /// <summary>
    /// 更新勋章（含规则，事务）
    /// </summary>
    public async Task<MedalOutput> UpdateAsync(long id, MedalInput input)
    {
        logger.LogInformation("正在更新勋章，ID: {Id}", id);

        var medal = await medalRepository.GetByIdAsync(id);
        if (medal == null)
        {
            logger.LogWarning("未找到要更新的勋章，ID: {Id}", id);
            throw new BusinessException("勋章不存在", ResultCode.NOT_FOUND);
        }

        if (string.IsNullOrWhiteSpace(input.Name))
        {
            throw new BusinessException("勋章名称不能为空", ResultCode.BAD_REQUEST);
        }

        if (string.IsNullOrWhiteSpace(input.Type))
        {
            throw new BusinessException("勋章类型不能为空", ResultCode.BAD_REQUEST);
        }

        medal.Name = input.Name.Trim();
        medal.Description = input.Description;
        medal.ImageUrl = input.ImageUrl;
        medal.SortOrder = input.SortOrder;
        medal.Type = Enum.Parse<MedalTypeEnum>(input.Type, true);
        medal.JournalId = input.JournalId;
        medal.UpdatedBy = "System";
        medal.UpdatedAt = DateTime.Now;

        try
        {
            await UseTranAsync(async () =>
            {
                var result = await medalRepository.UpdateAsync(medal);
                if (!result)
                {
                    throw new BusinessException("更新勋章失败", ResultCode.GLOBAL_ERROR);
                }

                // 删除旧规则，重新插入新规则
                await Context.Updateable<MedalRule>()
                    .SetColumns(r => new MedalRule { IsDeleted = true, UpdatedBy = "System", UpdatedAt = DateTime.Now })
                    .Where(r => r.MedalId == medal.Id)
                    .ExecuteCommandAsync();

                if (input.Rules != null && input.Rules.Count > 0)
                {
                    await InsertRulesAsync(medal.Id, input.Rules);
                }
            });
        }
        catch (BusinessException)
        {
            throw;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "勋章更新事务失败，ID: {Id}", id);
            throw new BusinessException("更新勋章失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("勋章更新成功，ID: {Id}", id);

        var rules = await GetRulesByMedalIdAsync(medal.Id);
        return BuildMedalOutput(medal, rules);
    }

    /// <summary>
    /// 删除勋章（软删除，含规则）
    /// </summary>
    public async Task DeleteAsync(long id)
    {
        logger.LogInformation("正在删除勋章，ID: {Id}", id);

        var medal = await medalRepository.GetByIdAsync(id);
        if (medal == null)
        {
            logger.LogWarning("未找到要删除的勋章，ID: {Id}", id);
            throw new BusinessException("勋章不存在", ResultCode.NOT_FOUND);
        }

        try
        {
            await UseTranAsync(async () =>
            {
                var result = await medalRepository.DeleteByIdAsync(id);
                if (!result)
                {
                    throw new BusinessException("删除勋章失败", ResultCode.GLOBAL_ERROR);
                }

                // 同时软删除关联规则
                await Context.Updateable<MedalRule>()
                    .SetColumns(r => new MedalRule { IsDeleted = true, UpdatedBy = "System", UpdatedAt = DateTime.Now })
                    .Where(r => r.MedalId == id)
                    .ExecuteCommandAsync();
            });
        }
        catch (BusinessException)
        {
            throw;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "勋章删除事务失败，ID: {Id}", id);
            throw new BusinessException("删除勋章失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("勋章删除成功，ID: {Id}", id);
    }

    /// <summary>
    /// 根据ID获取勋章（含规则）
    /// </summary>
    public async Task<MedalOutput> GetByIdAsync(long id)
    {
        logger.LogInformation("正在获取勋章信息，ID: {Id}", id);

        var medal = await medalRepository.GetByIdAsync(id);
        if (medal == null)
        {
            logger.LogWarning("未找到勋章，ID: {Id}", id);
            throw new BusinessException("勋章不存在", ResultCode.NOT_FOUND);
        }

        var rules = await GetRulesByMedalIdAsync(medal.Id);
        return BuildMedalOutput(medal, rules);
    }

    /// <summary>
    /// 分页查询勋章列表（含规则）
    /// </summary>
    public async Task<PageListModel<MedalOutput>> GetListAsync(MedalQueryInput input)
    {
        logger.LogInformation("正在查询勋章列表，页码: {PageIndex}, 每页条数: {PageSize}", input.PageIndex, input.PageSize);

        if (input.PageIndex <= 0)
        {
            throw new BusinessException("页码必须大于0", ResultCode.BAD_REQUEST);
        }

        if (input.PageSize <= 0 || input.PageSize > 100)
        {
            throw new BusinessException("每页条数必须在1-100之间", ResultCode.BAD_REQUEST);
        }

        RefAsync<int> totalNumber = 0;
        var medals = await medalRepository.Queryable()
                .WhereIF(!string.IsNullOrWhiteSpace(input.Name), m => m.Name.Contains(input.Name))
                .WhereIF(!string.IsNullOrWhiteSpace(input.Type), m => m.Type.ToString() == input.Type)
                .OrderBy(m => m.SortOrder)
                .OrderByDescending(m => m.CreatedAt)
                .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber);

        // 批量查询所有勋章的规则
        var medalIds = medals.Select(m => m.Id).ToList();
        var allRules = await Context.Queryable<MedalRule>()
            .Where(r => medalIds.Contains(r.MedalId) && !r.IsDeleted)
            .ToListAsync();

        var rulesDict = allRules.GroupBy(r => r.MedalId)
            .ToDictionary(g => g.Key, g => g.OrderBy(r => r.RuleOrder).Select(r => MapRuleOutput(r)).ToList());

        var pageResult = medals.Select(m => BuildMedalOutput(m, rulesDict.GetValueOrDefault(m.Id))).ToList();

        var result = new PageListModel<MedalOutput>(new List<MedalOutput>(), input.PageIndex, input.PageSize, totalNumber);
        result.Result = pageResult;
        return result;
    }

    /// <summary>
    /// 更新勋章启用/禁用状态
    /// </summary>
    public async Task<bool> UpdateStatusAsync(long id)
    {
        var medal = await medalRepository.GetByIdAsync(id);
        if (medal == null)
        {
            logger.LogWarning("未找到要更新状态的勋章，ID: {Id}", id);
            throw new BusinessException("勋章不存在", ResultCode.NOT_FOUND);
        }

        medal.Status = medal.Status == 0 ? 1 : 0;
        medal.UpdatedBy = "System";
        medal.UpdatedAt = DateTime.Now;

        var result = await medalRepository.UpdateAsync(medal);
        if (!result)
        {
            logger.LogError("勋章状态更新失败，ID: {Id}", id);
            throw new BusinessException("更新勋章状态失败", ResultCode.GLOBAL_ERROR);
        }
        logger.LogInformation("勋章状态更新成功，ID: {Id}, Status: {Status}", id, medal.Status);
        return result;

    }

    /// <summary>
    /// 获取勋章的规则列表
    /// </summary>
    public async Task<List<MedalRuleOutput>> GetRulesByMedalIdAsync(long medalId)
    {
        var rules = await Context.Queryable<MedalRule>()
            .Where(r => r.MedalId == medalId && !r.IsDeleted)
            .OrderBy(r => r.RuleOrder)
            .ToListAsync();

        return rules.Select(r => MapRuleOutput(r)).ToList();
    }

    /// <summary>
    /// 获取所有启用勋章列表（含当前用户拥有状态）
    /// </summary>
    public async Task<List<WxMedalListOutput>> GetAllMedalsAsync(long userId)
    {
        logger.LogInformation("正在获取所有勋章列表，用户ID: {UserId}", userId);

        var medals = await medalRepository.Queryable()
            .Where(m => m.Status == 1)
            .OrderBy(m => m.SortOrder)
            .OrderByDescending(m => m.CreatedAt)
            .ToListAsync();

        var userMedals = await Context.Queryable<UserMedal>()
            .Where(um => um.UserId == userId && um.Status == (int)UserMedalStatusEnum.Awarded)
            .ToListAsync();

        var userMedalDict = userMedals.ToDictionary(um => um.MedalId, um => um.AwardedAt);

        return medals.Select(m => new WxMedalListOutput
        {
            Id = m.Id,
            Name = m.Name,
            Description = m.Description,
            ImageUrl = m.ImageUrl,
            SortOrder = m.SortOrder,
            Type = m.Type.ToString(),
            IsOwned = userMedalDict.ContainsKey((int)m.Id),
            AwardedAt = userMedalDict.TryGetValue((int)m.Id, out var awardedAt) ? awardedAt : null
        }).ToList();
    }

    /// <summary>
    /// 获取用户已拥有的勋章列表
    /// </summary>
    public async Task<List<WxUserMedalOutput>> GetUserMedalsAsync(long userId)
    {
        logger.LogInformation("正在获取用户勋章列表，用户ID: {UserId}", userId);

        var result = await Context.Queryable<UserMedal>()
            .InnerJoin<Medal>((um, m) => um.MedalId == m.Id)
            .Where((um, m) => um.UserId == userId && um.Status == (int)UserMedalStatusEnum.Awarded)
            .OrderByDescending((um, m) => um.AwardedAt)
            .Select((um, m) => new WxUserMedalOutput
            {
                MedalId = m.Id,
                Name = m.Name,
                Description = m.Description,
                ImageUrl = m.ImageUrl,
                Type = m.Type.ToString(),
                AwardedAt = um.AwardedAt,
                Status = um.Status.ToString()
            })
            .ToListAsync();

        return result;
    }

    /// <summary>
    /// 激活/获得勋章
    /// </summary>
    public async Task ActivateMedalAsync(long userId, WxMedalActivateInput input)
    {
        logger.LogInformation("用户正在激活勋章，用户ID: {UserId}, 勋章ID: {MedalId}", userId, input.MedalId);

        if (input.MedalId <= 0)
        {
            throw new BusinessException("勋章ID无效", ResultCode.BAD_REQUEST);
        }

        var medal = await medalRepository.GetByIdAsync(input.MedalId);
        if (medal == null)
        {
            logger.LogWarning("未找到要激活的勋章，勋章ID: {MedalId}", input.MedalId);
            throw new BusinessException("勋章不存在", ResultCode.NOT_FOUND);
        }

        if (medal.Status != 1)
        {
            throw new BusinessException("该勋章当前不可获得", ResultCode.BAD_REQUEST);
        }

        // 规则校验
        var (passed, failReason) = await ValidateMedalRulesAsync(medal.Id, userId);
        if (!passed)
        {
            logger.LogWarning("勋章规则校验未通过，用户ID: {UserId}, 勋章ID: {MedalId}, 原因: {Reason}", userId, input.MedalId, failReason);
            throw new BusinessException(failReason!, ResultCode.BAD_REQUEST);
        }

        var existingUserMedal = await Context.Queryable<UserMedal>()
            .Where(um => um.UserId == userId && um.MedalId == (int)input.MedalId && um.Status == (int)UserMedalStatusEnum.Awarded)
            .FirstAsync();

        if (existingUserMedal != null)
        {
            throw new BusinessException("您已拥有该勋章", ResultCode.BAD_REQUEST);
        }

        var userMedal = new UserMedal
        {
            UserId = userId,
            MedalId = (int)input.MedalId,
            AwardedAt = DateTime.Now,
            Type = (UserMedalTypeEnum)medal.Type,
            Status = (int)UserMedalStatusEnum.Awarded,
            CreatedBy = "System",
            UpdatedBy = "System",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now,
            IsDeleted = false
        };

        var insertResult = await Context.Insertable(userMedal).ExecuteCommandAsync();
        if (insertResult <= 0)
        {
            logger.LogError("勋章激活失败，用户ID: {UserId}, 勋章ID: {MedalId}", userId, input.MedalId);
            throw new BusinessException("激活勋章失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("勋章激活成功，用户ID: {UserId}, 勋章ID: {MedalId}", userId, input.MedalId);
    }

    /// <summary>
    /// 获取规则配置中可用的目标表列表
    /// </summary>
    public Task<List<MedalRuleTableOptionOutput>> GetAvailableTablesAsync()
    {
        var tables = medalRuleConfig.Value.Tables?.Select(t => new MedalRuleTableOptionOutput
        {
            TableName = t.TableName,
            DisplayName = t.DisplayName
        }).ToList() ?? new List<MedalRuleTableOptionOutput>();

        return Task.FromResult(tables);
    }

    /// <summary>
    /// 获取指定表的可用字段列表
    /// </summary>
    public Task<List<MedalRuleFieldOptionOutput>> GetTableFieldsAsync(string tableName)
    {
        var table = medalRuleConfig.Value.Tables?.FirstOrDefault(t => t.TableName == tableName);
        if (table == null)
        {
            return Task.FromResult(new List<MedalRuleFieldOptionOutput>());
        }

        var fields = table.Fields.Select(f => new MedalRuleFieldOptionOutput
        {
            FieldName = f.FieldName,
            DisplayName = f.DisplayName
        }).ToList();

        return Task.FromResult(fields);
    }

    #region 私有辅助方法

    /// <summary>
    /// 批量插入规则
    /// </summary>
    private async Task InsertRulesAsync(long medalId, List<MedalRuleInput> ruleInputs)
    {
        var rules = ruleInputs.Select(r => new MedalRule
        {
            MedalId = medalId,
            TargetTable = r.TargetTable,
            TargetField = r.TargetField,
            Operator = r.Operator,
            ThresholdValue = r.ThresholdValue,
            FilterCondition = r.FilterCondition,
            DateRangeType = r.DateRangeType,
            DateRangeStart = r.DateRangeStart,
            DateRangeEnd = r.DateRangeEnd,
            LogicOperator = r.LogicOperator,
            RuleOrder = r.RuleOrder,
            Description = r.Description,
            CreatedBy = "System",
            UpdatedBy = "System",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now,
            IsDeleted = false
        }).ToList();

        var count = await Context.Insertable(rules).ExecuteCommandAsync();
        if (count <= 0)
        {
            logger.LogError("勋章规则插入失败，MedalId: {MedalId}", medalId);
            throw new BusinessException("创建勋章规则失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("勋章规则创建成功，MedalId: {MedalId}, 规则数: {Count}", medalId, rules.Count);
    }

    /// <summary>
    /// 构建MedalOutput
    /// </summary>
    private static MedalOutput BuildMedalOutput(Medal medal, List<MedalRuleOutput>? rules)
    {
        return new MedalOutput
        {
            Id = medal.Id,
            Name = medal.Name,
            Description = medal.Description,
            ImageUrl = medal.ImageUrl,
            SortOrder = medal.SortOrder,
            Type = medal.Type.ToString(),
            JournalId = medal.JournalId,
            Status = (DefaultStatusEnum)medal.Status,
            Rules = rules,
            CreatedBy = medal.CreatedBy,
            CreatedAt = medal.CreatedAt,
            UpdatedBy = medal.UpdatedBy,
            UpdatedAt = medal.UpdatedAt
        };
    }

    /// <summary>
    /// 映射规则实体到输出DTO
    /// </summary>
    private static MedalRuleOutput MapRuleOutput(MedalRule r)
    {
        return new MedalRuleOutput
        {
            Id = r.Id,
            MedalId = r.MedalId,
            TargetTable = r.TargetTable,
            TargetField = r.TargetField,
            Operator = r.Operator,
            ThresholdValue = r.ThresholdValue,
            FilterCondition = r.FilterCondition,
            DateRangeType = r.DateRangeType,
            DateRangeStart = r.DateRangeStart,
            DateRangeEnd = r.DateRangeEnd,
            LogicOperator = r.LogicOperator,
            RuleOrder = r.RuleOrder,
            Description = r.Description,
            CreatedAt = r.CreatedAt,
            UpdatedAt = r.UpdatedAt
        };
    }

    /// <summary>
    /// 校验勋章规则是否满足
    /// </summary>
    /// <param name="medalId">勋章ID</param>
    /// <param name="userId">用户ID</param>
    /// <returns>(是否通过, 失败原因)</returns>
    private async Task<(bool passed, string? failReason)> ValidateMedalRulesAsync(long medalId, long userId)
    {
        var rules = await Context.Queryable<MedalRule>()
            .Where(r => r.MedalId == medalId && !r.IsDeleted)
            .OrderBy(r => r.RuleOrder)
            .ToListAsync();

        if (!rules.Any())
        {
            return (true, null);
        }

        var failReasons = new List<string>();

        foreach (var rule in rules)
        {
            var rulePassed = await EvaluateRuleAsync(rule, userId);

            if (!rulePassed)
            {
                var reason = !string.IsNullOrWhiteSpace(rule.Description)
                    ? rule.Description
                    : $"未满足条件: {rule.TargetField} {rule.Operator} {rule.ThresholdValue}";
                failReasons.Add(reason);
            }

            var logicOp = rule.LogicOperator?.ToUpper() ?? "AND";

            if (logicOp == "AND" && !rulePassed)
            {
                return (false, $"未满足获得条件：{string.Join("；", failReasons)}");
            }

            if (logicOp == "OR" && rulePassed)
            {
                return (true, null);
            }
        }

        // AND 模式下所有规则都通过才到这里
        // OR 模式下所有规则都没通过才到这里
        var firstLogicOp = rules.First().LogicOperator?.ToUpper() ?? "AND";
        if (firstLogicOp == "AND")
        {
            return (true, null);
        }
        else
        {
            return (false, $"未满足获得条件：{string.Join("；", failReasons)}");
        }
    }

    /// <summary>
    /// 评估单条规则是否满足
    /// </summary>
    /// <param name="rule">规则配置</param>
    /// <param name="userId">用户ID</param>
    /// <returns>规则是否满足</returns>
    private async Task<bool> EvaluateRuleAsync(MedalRule rule, long userId)
    {
        try
        {
            var sql = $"SELECT COUNT(1) FROM [{rule.TargetTable}] WHERE [{rule.TargetField}] {rule.Operator} @ThresholdValue AND IsDeleted = 0 AND UserId = @UserId";
            var parameters = new List<SugarParameter>
            {
                new SugarParameter("@ThresholdValue", rule.ThresholdValue),
                new SugarParameter("@UserId", userId)
            };

            // 处理额外筛选条件
            if (!string.IsNullOrWhiteSpace(rule.FilterCondition))
            {
                var filters = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(rule.FilterCondition);
                if (filters != null)
                {
                    var index = 0;
                    foreach (var kv in filters)
                    {
                        var paramName = $"@Filter_{index}";
                        sql += $" AND [{kv.Key}] = {paramName}";
                        var paramValue = kv.Value.ValueKind switch
                        {
                            JsonValueKind.Number => kv.Value.GetInt32() as object,
                            JsonValueKind.String => kv.Value.GetString() as object,
                            JsonValueKind.True => true as object,
                            JsonValueKind.False => false as object,
                            _ => kv.Value.GetRawText()
                        };
                        parameters.Add(new SugarParameter(paramName, paramValue!));
                        index++;
                    }
                }
            }

            // 处理时间范围
            var dateRange = GetDateRange(rule);
            if (dateRange.HasValue)
            {
                sql += " AND CreatedAt >= @DateStart AND CreatedAt <= @DateEnd";
                parameters.Add(new SugarParameter("@DateStart", dateRange.Value.start));
                parameters.Add(new SugarParameter("@DateEnd", dateRange.Value.end));
            }

            var count = await Context.Ado.GetIntAsync(sql, parameters.ToArray());
            return count > 0;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "规则评估异常，规则ID: {RuleId}, 目标表: {Table}, 目标字段: {Field}",
                rule.Id, rule.TargetTable, rule.TargetField);
            return false;
        }
    }

    /// <summary>
    /// 根据规则的时间范围类型计算起止时间
    /// </summary>
    private static (DateTime start, DateTime end)? GetDateRange(MedalRule rule)
    {
        var now = DateTime.Now;

        return rule.DateRangeType?.ToLower() switch
        {
            "currentmonth" => (new DateTime(now.Year, now.Month, 1), now),
            "currentweek" => (now.AddDays(-(int)now.DayOfWeek), now),
            "last7days" => (now.AddDays(-7), now),
            "custom" when rule.DateRangeStart.HasValue && rule.DateRangeEnd.HasValue => (rule.DateRangeStart.Value, rule.DateRangeEnd.Value),
            _ => null
        };
    }

    #endregion
}
