using HoneyBox.Admin.Business.Models;
using HoneyBox.Admin.Business.Models.Advert;
using HoneyBox.Admin.Business.Services.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Admin.Business.Services;

/// <summary>
/// 广告管理服务实现
/// </summary>
public class AdvertService : IAdvertService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<AdvertService> _logger;

    public AdvertService(
        HoneyBoxDbContext dbContext,
        ILogger<AdvertService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    #region 广告管理

    /// <inheritdoc />
    public async Task<PagedResult<AdvertResponse>> GetAdvertsAsync(AdvertListRequest request)
    {
        var query = _dbContext.Adverts.AsNoTracking();

        // 应用类型过滤
        if (request.TypeId.HasValue)
        {
            query = query.Where(a => a.Type == request.TypeId.Value);
        }

        // 获取总数
        var total = await query.CountAsync();

        // 获取列表
        var adverts = await query
            .OrderBy(a => a.Sort)
            .ThenByDescending(a => a.Id)
            .Skip(request.Skip)
            .Take(request.PageSize)
            .ToListAsync();

        // 获取类型名称映射
        var typeIds = adverts.Select(a => (int)a.Type).Distinct().ToList();
        var types = await _dbContext.AdvertTypes
            .AsNoTracking()
            .Where(t => typeIds.Contains(t.Id))
            .ToDictionaryAsync(t => t.Id, t => t.Name);

        // 映射结果
        var list = adverts.Select(a => MapToResponse(a, types)).ToList();

        return PagedResult<AdvertResponse>.Create(list, total, request.Page, request.PageSize);
    }


    /// <inheritdoc />
    public async Task<AdvertResponse?> GetAdvertByIdAsync(int id)
    {
        var advert = await _dbContext.Adverts
            .AsNoTracking()
            .FirstOrDefaultAsync(a => a.Id == id);

        if (advert == null)
            return null;

        // 获取类型名称
        var typeName = await _dbContext.AdvertTypes
            .AsNoTracking()
            .Where(t => t.Id == advert.Type)
            .Select(t => t.Name)
            .FirstOrDefaultAsync() ?? "未知类型";

        return MapToResponse(advert, new Dictionary<int, string> { { advert.Type, typeName } });
    }

    /// <inheritdoc />
    public async Task<int> CreateAdvertAsync(AdvertCreateRequest request)
    {
        // 验证请求
        await ValidateAdvertRequest(request);

        var now = DateTime.Now;
        var advert = new Advert
        {
            Type = (byte)request.TypeId,
            ImgUrl = request.ImageUrl,
            Sort = request.Sort,
            Ttype = (byte)request.JumpType,
            CouponId = request.CouponId ?? 0,
            GoodsId = request.GoodsId ?? 0,
            Url = request.UrlLink,
            CreatedAt = now,
            UpdatedAt = now
        };

        _dbContext.Adverts.Add(advert);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("创建广告成功: Id={Id}, TypeId={TypeId}", advert.Id, request.TypeId);

        return advert.Id;
    }

    /// <inheritdoc />
    public async Task<bool> UpdateAdvertAsync(int id, AdvertUpdateRequest request)
    {
        var advert = await _dbContext.Adverts.FirstOrDefaultAsync(a => a.Id == id);
        if (advert == null)
        {
            throw new BusinessException(BusinessErrorCodes.NotFound, "广告不存在");
        }

        // 验证请求
        await ValidateAdvertRequest(request);

        advert.Type = (byte)request.TypeId;
        advert.ImgUrl = request.ImageUrl;
        advert.Sort = request.Sort;
        advert.Ttype = (byte)request.JumpType;
        advert.CouponId = request.CouponId ?? 0;
        advert.GoodsId = request.GoodsId ?? 0;
        advert.Url = request.UrlLink;
        advert.UpdatedAt = DateTime.Now;

        var result = await _dbContext.SaveChangesAsync() > 0;

        _logger.LogInformation("更新广告成功: Id={Id}", id);

        return result;
    }

    /// <inheritdoc />
    public async Task<bool> DeleteAdvertAsync(int id)
    {
        var advert = await _dbContext.Adverts.FirstOrDefaultAsync(a => a.Id == id);
        if (advert == null)
        {
            throw new BusinessException(BusinessErrorCodes.NotFound, "广告不存在");
        }

        _dbContext.Adverts.Remove(advert);
        var result = await _dbContext.SaveChangesAsync() > 0;

        _logger.LogInformation("删除广告成功: Id={Id}", id);

        return result;
    }

    #endregion

    #region 广告类型管理

    /// <inheritdoc />
    public async Task<List<AdvertTypeResponse>> GetAdvertTypesAsync()
    {
        // 获取所有类型
        var types = await _dbContext.AdvertTypes
            .AsNoTracking()
            .OrderBy(t => t.Sort)
            .ThenBy(t => t.Id)
            .ToListAsync();

        // 获取每个类型下的广告数量
        var typeCounts = await _dbContext.Adverts
            .AsNoTracking()
            .GroupBy(a => a.Type)
            .Select(g => new { TypeId = g.Key, Count = g.Count() })
            .ToDictionaryAsync(x => (int)x.TypeId, x => x.Count);

        return types.Select(t => new AdvertTypeResponse
        {
            Id = t.Id,
            Name = t.Name,
            Sort = t.Sort,
            AdvertCount = typeCounts.GetValueOrDefault(t.Id, 0)
        }).ToList();
    }

    /// <inheritdoc />
    public async Task<int> CreateAdvertTypeAsync(AdvertTypeCreateRequest request)
    {
        // 验证名称
        if (string.IsNullOrWhiteSpace(request.Name))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "类型名称不能为空");
        }

        // 检查名称是否已存在
        var exists = await _dbContext.AdvertTypes
            .AnyAsync(t => t.Name == request.Name);
        if (exists)
        {
            throw new BusinessException(BusinessErrorCodes.Conflict, "该类型名称已存在");
        }

        var now = DateTime.Now;
        var advertType = new AdvertType
        {
            Name = request.Name,
            Sort = request.Sort,
            CreatedAt = now,
            UpdatedAt = now
        };

        _dbContext.AdvertTypes.Add(advertType);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("创建广告类型成功: Id={Id}, Name={Name}", advertType.Id, advertType.Name);

        return advertType.Id;
    }


    /// <inheritdoc />
    public async Task<bool> UpdateAdvertTypeAsync(int id, AdvertTypeUpdateRequest request)
    {
        var advertType = await _dbContext.AdvertTypes.FirstOrDefaultAsync(t => t.Id == id);
        if (advertType == null)
        {
            throw new BusinessException(BusinessErrorCodes.NotFound, "广告类型不存在");
        }

        // 验证名称
        if (string.IsNullOrWhiteSpace(request.Name))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "类型名称不能为空");
        }

        // 检查名称是否被其他类型使用
        var exists = await _dbContext.AdvertTypes
            .AnyAsync(t => t.Name == request.Name && t.Id != id);
        if (exists)
        {
            throw new BusinessException(BusinessErrorCodes.Conflict, "该类型名称已被其他类型使用");
        }

        advertType.Name = request.Name;
        advertType.Sort = request.Sort;
        advertType.UpdatedAt = DateTime.Now;

        var result = await _dbContext.SaveChangesAsync() > 0;

        _logger.LogInformation("更新广告类型成功: Id={Id}, Name={Name}", id, advertType.Name);

        return result;
    }

    /// <inheritdoc />
    public async Task<bool> DeleteAdvertTypeAsync(int id)
    {
        var advertType = await _dbContext.AdvertTypes.FirstOrDefaultAsync(t => t.Id == id);
        if (advertType == null)
        {
            throw new BusinessException(BusinessErrorCodes.NotFound, "广告类型不存在");
        }

        // 检查该类型下是否有广告
        var hasAdverts = await _dbContext.Adverts.AnyAsync(a => a.Type == id);
        if (hasAdverts)
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "删除失败：该类型下仍有关联的广告，请先删除或移动这些广告");
        }

        _dbContext.AdvertTypes.Remove(advertType);
        var result = await _dbContext.SaveChangesAsync() > 0;

        _logger.LogInformation("删除广告类型成功: Id={Id}, Name={Name}", id, advertType.Name);

        return result;
    }

    #endregion

    #region Private Helper Methods

    /// <summary>
    /// 验证广告请求参数
    /// </summary>
    private async Task ValidateAdvertRequest(AdvertCreateRequest request)
    {
        // 验证图片URL
        if (string.IsNullOrWhiteSpace(request.ImageUrl))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "广告图片不能为空");
        }

        // 验证类型是否存在
        var typeExists = await _dbContext.AdvertTypes.AnyAsync(t => t.Id == request.TypeId);
        if (!typeExists)
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "选择的广告类型无效");
        }

        // 验证跳转类型
        if (request.JumpType < 0 || request.JumpType > 5)
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "跳转类型无效");
        }

        // 根据跳转类型验证关联字段
        switch (request.JumpType)
        {
            case AdvertJumpTypes.Coupon:
                if (!request.CouponId.HasValue || request.CouponId <= 0)
                {
                    throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请选择关联的优惠券");
                }
                break;
            case AdvertJumpTypes.YiFanShang:
            case AdvertJumpTypes.WuXianShang:
            case AdvertJumpTypes.LianJiShang:
                if (!request.GoodsId.HasValue || request.GoodsId <= 0)
                {
                    throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请选择关联的盒子");
                }
                break;
            case AdvertJumpTypes.CustomUrl:
                if (string.IsNullOrWhiteSpace(request.UrlLink))
                {
                    throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请输入跳转链接");
                }
                break;
        }
    }

    /// <summary>
    /// 映射广告实体到响应模型
    /// </summary>
    private AdvertResponse MapToResponse(Advert advert, Dictionary<int, string> typeNames)
    {
        return new AdvertResponse
        {
            Id = advert.Id,
            TypeId = advert.Type,
            TypeName = typeNames.GetValueOrDefault(advert.Type, "未知类型"),
            ImageUrl = advert.ImgUrl,
            Sort = advert.Sort,
            JumpType = advert.Ttype ?? 0,
            JumpTypeName = AdvertJumpTypes.GetJumpTypeName(advert.Ttype ?? 0),
            CouponId = advert.CouponId == 0 ? null : advert.CouponId,
            GoodsId = advert.GoodsId == 0 ? null : advert.GoodsId,
            UrlLink = advert.Url,
            CreatedAt = advert.CreatedAt,
            UpdatedAt = advert.UpdatedAt
        };
    }

    #endregion
}
