using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.CheckIn;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Repository;
using SqlSugar;

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// 签到配置服务实现
/// </summary>
public class CheckInConfigService(
    BaseRepository<CheckInConfig> checkInConfigRepository,
    ILogger<CheckInConfigService> logger)
    : BaseRepository<CheckInConfig>, ICheckInConfigService
{
    /// <summary>
    /// 创建签到配置
    /// </summary>
    public async Task<CheckInConfigOutput> CreateAsync(CheckInConfigInput input)
    {
        logger.LogInformation("正在创建签到配置，DayNumber: {DayNumber}, Type: {Type}", input.DayNumber, input.Type);

        if (input.DayNumber <= 0)
        {
            throw new BusinessException("连续签到天数必须大于0", ResultCode.BAD_REQUEST);
        }

        if (input.RewardPoints < 0)
        {
            throw new BusinessException("奖励积分不能为负数", ResultCode.BAD_REQUEST);
        }

        if (input.BonusPoints < 0)
        {
            throw new BusinessException("额外奖励积分不能为负数", ResultCode.BAD_REQUEST);
        }

        // 检查同类型下是否已存在相同天数配置
        var exists = await checkInConfigRepository.Context.Queryable<CheckInConfig>()
            .Where(c => c.Type == input.Type && c.DayNumber == input.DayNumber && !c.IsDeleted)
            .AnyAsync();

        if (exists)
        {
            throw new BusinessException($"该类型下已存在连续{input.DayNumber}天的配置", ResultCode.BAD_REQUEST);
        }

        var config = new CheckInConfig
        {
            DayNumber = input.DayNumber,
            RewardPoints = input.RewardPoints,
            BonusPoints = input.BonusPoints,
            Type = input.Type,
            Status = (int)DefaultStatusEnum.Active,
            CreatedBy = "System",
            UpdatedBy = "System",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now,
            IsDeleted = false
        };

        var result = await checkInConfigRepository.InsertAsync(config);
        if (!result)
        {
            throw new BusinessException("创建签到配置失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("签到配置创建成功，ID: {Id}", config.Id);
        return MapToOutput(config);
    }

    /// <summary>
    /// 更新签到配置
    /// </summary>
    public async Task<CheckInConfigOutput> UpdateAsync(long id, CheckInConfigInput input)
    {
        logger.LogInformation("正在更新签到配置，ID: {Id}", id);

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

        if (input.DayNumber <= 0)
        {
            throw new BusinessException("连续签到天数必须大于0", ResultCode.BAD_REQUEST);
        }

        if (input.RewardPoints < 0)
        {
            throw new BusinessException("奖励积分不能为负数", ResultCode.BAD_REQUEST);
        }

        if (input.BonusPoints < 0)
        {
            throw new BusinessException("额外奖励积分不能为负数", ResultCode.BAD_REQUEST);
        }

        // 检查同类型下是否已存在相同天数配置（排除自身）
        var exists = await checkInConfigRepository.Context.Queryable<CheckInConfig>()
            .Where(c => c.Type == input.Type && c.DayNumber == input.DayNumber && c.Id != id && !c.IsDeleted)
            .AnyAsync();

        if (exists)
        {
            throw new BusinessException($"该类型下已存在连续{input.DayNumber}天的配置", ResultCode.BAD_REQUEST);
        }

        config.DayNumber = input.DayNumber;
        config.RewardPoints = input.RewardPoints;
        config.BonusPoints = input.BonusPoints;
        config.Type = input.Type;
        config.UpdatedBy = "System";
        config.UpdatedAt = DateTime.Now;

        var updateResult = await checkInConfigRepository.UpdateAsync(config);
        if (!updateResult)
        {
            throw new BusinessException("更新签到配置失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("签到配置更新成功，ID: {Id}", id);
        return MapToOutput(config);
    }

    /// <summary>
    /// 删除签到配置（软删除）
    /// </summary>
    public async Task DeleteAsync(long id)
    {
        logger.LogInformation("正在删除签到配置，ID: {Id}", id);

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

        var result = await checkInConfigRepository.Context.Updateable<CheckInConfig>()
            .SetColumns(c => new CheckInConfig
            {
                IsDeleted = true,
                UpdatedBy = "System",
                UpdatedAt = DateTime.Now
            })
            .Where(c => c.Id == id)
            .ExecuteCommandAsync();

        if (result <= 0)
        {
            throw new BusinessException("删除签到配置失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("签到配置删除成功，ID: {Id}", id);
    }

    /// <summary>
    /// 根据ID获取签到配置
    /// </summary>
    public async Task<CheckInConfigOutput> GetByIdAsync(long id)
    {
        var config = await checkInConfigRepository.GetByIdAsync(id);
        if (config == null)
        {
            throw new BusinessException("签到配置不存在", ResultCode.NOT_FOUND);
        }

        return MapToOutput(config);
    }

    /// <summary>
    /// 分页查询签到配置列表
    /// </summary>
    public async Task<PageListModel<CheckInConfigOutput>> GetListAsync(CheckInConfigQueryInput 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 configs = await checkInConfigRepository.Queryable()
                .Where(c => !c.IsDeleted)
                .WhereIF(input.Type.HasValue, c => c.Type == input.Type.Value)
                .OrderBy(c => c.Type)
                .OrderBy(c => c.DayNumber)
                .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber);

        var pageResult = configs.Select(MapToOutput).ToList();

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

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

        config.Status = config.Status == (int)DefaultStatusEnum.Active
            ? (int)DefaultStatusEnum.Inactive
            : (int)DefaultStatusEnum.Active;
        config.UpdatedBy = "System";
        config.UpdatedAt = DateTime.Now;

        var result = await checkInConfigRepository.UpdateAsync(config);
        if (!result)
        {
            logger.LogError("签到配置状态更新失败，ID: {Id}", id);
            throw new BusinessException("更新签到配置状态失败", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("签到配置状态更新成功，ID: {Id}, Status: {Status}", id, config.Status);
        return result;
    }

    /// <summary>
    /// 实体映射为输出DTO
    /// </summary>
    private static CheckInConfigOutput MapToOutput(CheckInConfig config)
    {
        return new CheckInConfigOutput
        {
            Id = config.Id,
            DayNumber = config.DayNumber,
            RewardPoints = config.RewardPoints,
            BonusPoints = config.BonusPoints,
            Type = config.Type,
            Status = config.Status,
            CreatedBy = config.CreatedBy,
            CreatedAt = config.CreatedAt,
            UpdatedBy = config.UpdatedBy,
            UpdatedAt = config.UpdatedAt
        };
    }
}
