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

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// 轮播图服务实现
/// </summary>
public class BannerService(
    BaseRepository<Banner> bannerRepository,
    OssService ossService,
    ILogger<BannerService> logger) : BaseRepository<Banner>, IBannerService
{
    /// <summary>
    /// 创建轮播图
    /// </summary>
    public async Task<BannerOutput> CreateAsync(BannerInput input)
    {
        ValidateInput(input);

        var banner = new Banner
        {
            Title = input.Title.Trim(),
            ImageUrl = input.ImageUrl.Trim(),
            Position = input.Position,
            TargetType = input.TargetType,
            TargetValue = NormalizeTargetValue(input),
            Sort = input.Sort,
            StartTime = input.StartTime,
            EndTime = input.EndTime,
            Remark = input.Remark,
            Status = (int)DefaultStatusEnum.Active,
            IsDeleted = false,
            CreatedBy = "System",
            CreatedAt = DateTime.Now,
            UpdatedBy = "System",
            UpdatedAt = DateTime.Now
        };

        var result = await bannerRepository.InsertAsync(banner);
        BusinessException.ThrowIf(!result, "创建轮播图失败", ResultCode.GLOBAL_ERROR);

        if (OssImageHelper.IsTempImage(banner.ImageUrl))
        {
            var helper = CreateImageHelper();
            banner.ImageUrl = await helper.MoveToFormalAsync(banner.ImageUrl, GetBannerFormalFolder(banner.Position, banner.Id));
            await bannerRepository.UpdateAsync(banner);
        }

        logger.LogInformation("轮播图创建成功：{Id}", banner.Id);
        return MapToOutput(banner);
    }

    /// <summary>
    /// 更新轮播图
    /// </summary>
    public async Task<BannerOutput> UpdateAsync(long id, BannerInput input)
    {
        ValidateInput(input);

        var banner = await GetValidBannerAsync(id);
        var newImageUrl = input.ImageUrl.Trim();
        if (OssImageHelper.IsTempImage(newImageUrl))
        {
            var helper = CreateImageHelper();
            newImageUrl = await helper.MoveToFormalAsync(newImageUrl, GetBannerFormalFolder(input.Position, banner.Id));
        }

        banner.Title = input.Title.Trim();
        banner.ImageUrl = newImageUrl;
        banner.Position = input.Position;
        banner.TargetType = input.TargetType;
        banner.TargetValue = NormalizeTargetValue(input);
        banner.Sort = input.Sort;
        banner.StartTime = input.StartTime;
        banner.EndTime = input.EndTime;
        banner.Remark = input.Remark;
        banner.UpdatedBy = "System";
        banner.UpdatedAt = DateTime.Now;

        var result = await bannerRepository.UpdateAsync(banner);
        BusinessException.ThrowIf(!result, "更新轮播图失败", ResultCode.GLOBAL_ERROR);

        logger.LogInformation("轮播图更新成功：{Id}", banner.Id);
        return MapToOutput(banner);
    }

    /// <summary>
    /// 删除轮播图
    /// </summary>
    public async Task DeleteAsync(long id)
    {
        await GetValidBannerAsync(id);

        var result = await bannerRepository.Context.Updateable<Banner>()
            .SetColumns(b => new Banner
            {
                IsDeleted = true,
                UpdatedBy = "System",
                UpdatedAt = DateTime.Now
            })
            .Where(b => b.Id == id && !b.IsDeleted)
            .ExecuteCommandAsync();

        BusinessException.ThrowIf(result <= 0, "删除轮播图失败", ResultCode.GLOBAL_ERROR);
        logger.LogInformation("轮播图删除成功：{Id}", id);
    }

    /// <summary>
    /// 根据ID获取轮播图
    /// </summary>
    public async Task<BannerOutput> GetByIdAsync(long id)
    {
        var banner = await GetValidBannerAsync(id);
        return MapToOutput(banner);
    }

    /// <summary>
    /// 分页查询轮播图列表
    /// </summary>
    public async Task<PageListModel<BannerOutput>> GetListAsync(BannerQueryInput input)
    {
        BusinessException.ThrowIf(input.PageIndex <= 0, "页码必须大于0", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.PageSize <= 0 || input.PageSize > 100, "每页条数必须在1-100之间", ResultCode.BAD_REQUEST);

        RefAsync<int> totalNumber = 0;
        var banners = await bannerRepository.Queryable()
            .Where(b => !b.IsDeleted)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Title), b => b.Title.Contains(input.Title!.Trim()))
            .WhereIF(input.Position.HasValue, b => b.Position == input.Position!.Value)
            .WhereIF(input.Status.HasValue, b => b.Status == input.Status!.Value)
            .OrderBy(b => b.Sort)
            .OrderByDescending(b => b.CreatedAt)
            .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber);

        var result = banners.Select(MapToOutput).ToList();
        return new PageListModel<BannerOutput>(result, input.PageIndex, input.PageSize, totalNumber);
    }

    /// <summary>
    /// 更新轮播图启用/禁用状态
    /// </summary>
    public async Task<bool> UpdateStatusAsync(long id)
    {
        var banner = await GetValidBannerAsync(id);
        banner.Status = banner.Status == (int)DefaultStatusEnum.Active
            ? (int)DefaultStatusEnum.Inactive
            : (int)DefaultStatusEnum.Active;
        banner.UpdatedBy = "System";
        banner.UpdatedAt = DateTime.Now;

        var result = await bannerRepository.UpdateAsync(banner);
        BusinessException.ThrowIf(!result, "更新轮播图状态失败", ResultCode.GLOBAL_ERROR);

        logger.LogInformation("轮播图状态更新成功：{Id}，状态：{Status}", id, banner.Status);
        return result;
    }

    /// <summary>
    /// 获取启用轮播图列表
    /// </summary>
    public async Task<List<BannerOutput>> GetEnabledListAsync(BannerPositionEnum position)
    {
        var now = DateTime.Now;
        var banners = await bannerRepository.Queryable()
            .Where(b => !b.IsDeleted)
            .Where(b => b.Status == (int)DefaultStatusEnum.Active)
            .Where(b => b.Position == position)
            .Where(b => b.StartTime == null || b.StartTime <= now)
            .Where(b => b.EndTime == null || b.EndTime >= now)
            .OrderBy(b => b.Sort)
            .OrderByDescending(b => b.CreatedAt)
            .ToListAsync();

        return banners.Select(MapToOutput).ToList();
    }

    private async Task<Banner> GetValidBannerAsync(long id)
    {
        var banner = await bannerRepository.Queryable()
            .Where(b => b.Id == id && !b.IsDeleted)
            .FirstAsync();

        BusinessException.ThrowIf(banner == null, "轮播图不存在", ResultCode.NOT_FOUND);
        return banner;
    }

    private static void ValidateInput(BannerInput input)
    {
        BusinessException.ThrowIf(string.IsNullOrWhiteSpace(input.Title), "标题不能为空", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.Title.Trim().Length > 100, "标题长度不能超过100个字符", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(string.IsNullOrWhiteSpace(input.ImageUrl), "轮播图不能为空", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.ImageUrl.Trim().Length > 500, "轮播图路径长度不能超过500个字符", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.Sort < 0, "排序值不能小于0", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.StartTime.HasValue && input.EndTime.HasValue && input.EndTime <= input.StartTime, "结束时间必须大于开始时间", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(input.TargetType != BannerTargetTypeEnum.None && string.IsNullOrWhiteSpace(input.TargetValue), "跳转值不能为空", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(!string.IsNullOrWhiteSpace(input.TargetValue) && input.TargetValue.Length > 500, "跳转值长度不能超过500个字符", ResultCode.BAD_REQUEST);
        BusinessException.ThrowIf(!string.IsNullOrWhiteSpace(input.Remark) && input.Remark.Length > 500, "备注长度不能超过500个字符", ResultCode.BAD_REQUEST);
    }

    private static string? NormalizeTargetValue(BannerInput input)
    {
        return input.TargetType == BannerTargetTypeEnum.None
            ? null
            : input.TargetValue?.Trim();
    }

    private OssImageHelper CreateImageHelper() => new(ossService, logger);

    private static string GetBannerFormalFolder(BannerPositionEnum position, long bannerId)
    {
        return $"banner/{position.ToString().ToLowerInvariant()}/{bannerId}";
    }

    private static BannerOutput MapToOutput(Banner banner)
    {
        return new BannerOutput
        {
            Id = banner.Id,
            Title = banner.Title,
            ImageUrl = banner.ImageUrl,
            Position = banner.Position,
            TargetType = banner.TargetType,
            TargetValue = banner.TargetValue,
            Sort = banner.Sort,
            StartTime = banner.StartTime,
            EndTime = banner.EndTime,
            Remark = banner.Remark,
            Status = banner.Status,
            CreatedBy = banner.CreatedBy,
            CreatedAt = banner.CreatedAt,
            UpdatedBy = banner.UpdatedBy,
            UpdatedAt = banner.UpdatedAt
        };
    }
}
