using HoneyBox.Admin.Business.Models.Dashboard;
using HoneyBox.Admin.Business.Services;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// DashboardService 单元测试
/// </summary>
public class DashboardServiceTests : IDisposable
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly DashboardService _service;
    private readonly Mock<ILogger<DashboardService>> _mockLogger;

    public DashboardServiceTests()
    {
        var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;

        _dbContext = new HoneyBoxDbContext(options);
        _mockLogger = new Mock<ILogger<DashboardService>>();
        _service = new DashboardService(_dbContext, _mockLogger.Object);
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }

    #region 仪表盘概览测试

    [Fact]
    public async Task GetOverview_ShouldReturnTodayRegistrations()
    {
        // Arrange
        SeedUsersWithDates();

        // Act
        var result = await _service.GetOverviewAsync();

        // Assert
        Assert.NotNull(result);
        Assert.True(result.TodayRegistrations >= 0);
    }

    [Fact]
    public async Task GetOverview_ShouldReturnTodayConsumption()
    {
        // Arrange
        SeedUsers(2);
        SeedOrdersWithDates();

        // Act
        var result = await _service.GetOverviewAsync();

        // Assert
        Assert.NotNull(result);
        Assert.True(result.TodayConsumption >= 0);
    }

    [Fact]
    public async Task GetOverview_ShouldReturnTotalUsers()
    {
        // Arrange
        SeedUsers(5);

        // Act
        var result = await _service.GetOverviewAsync();

        // Assert
        Assert.NotNull(result);
        Assert.Equal(5, result.TotalUsers);
    }

    [Fact]
    public async Task GetOverview_ShouldReturnTotalOrders()
    {
        // Arrange
        SeedUsers(1);
        SeedOrders(10);

        // Act
        var result = await _service.GetOverviewAsync();

        // Assert
        Assert.NotNull(result);
        Assert.Equal(10, result.TotalOrders);
    }

    [Fact]
    public async Task GetOverview_ShouldReturnTotalConsumption()
    {
        // Arrange
        SeedUsers(1);
        SeedOrders(3);

        // Act
        var result = await _service.GetOverviewAsync();

        // Assert
        Assert.NotNull(result);
        Assert.True(result.TotalConsumption > 0);
    }

    #endregion

    #region 广告账户测试

    [Fact]
    public async Task GetAdAccounts_ShouldReturnAllAdverts()
    {
        // Arrange
        SeedAdverts(5);

        // Act
        var result = await _service.GetAdAccountsAsync();

        // Assert
        Assert.NotNull(result);
        Assert.Equal(5, result.Count);
    }

    [Fact]
    public async Task GetAdAccounts_ShouldReturnOrderedBySort()
    {
        // Arrange
        SeedAdverts(3);

        // Act
        var result = await _service.GetAdAccountsAsync();

        // Assert
        Assert.NotNull(result);
        for (int i = 0; i < result.Count - 1; i++)
        {
            Assert.True(result[i].Sort <= result[i + 1].Sort);
        }
    }

    [Fact]
    public async Task CreateAdAccount_ShouldCreateNewAdvert()
    {
        // Arrange
        var request = new AdAccountCreateRequest
        {
            ImgUrl = "http://test.com/ad.jpg",
            Url = "http://test.com/link",
            Sort = 1,
            Type = 1
        };

        // Act
        var id = await _service.CreateAdAccountAsync(request);

        // Assert
        Assert.True(id > 0);
        var advert = await _dbContext.Adverts.FindAsync(id);
        Assert.NotNull(advert);
        Assert.Equal(request.ImgUrl, advert.ImgUrl);
        Assert.Equal(request.Url, advert.Url);
    }

    [Fact]
    public async Task DeleteAdAccount_ShouldDeleteExistingAdvert()
    {
        // Arrange
        SeedAdverts(1);
        var advert = await _dbContext.Adverts.FirstAsync();

        // Act
        var result = await _service.DeleteAdAccountAsync(advert.Id);

        // Assert
        Assert.True(result);
        var deleted = await _dbContext.Adverts.FindAsync(advert.Id);
        Assert.Null(deleted);
    }

    [Fact]
    public async Task DeleteAdAccount_ShouldReturnFalseForNonExistent()
    {
        // Act
        var result = await _service.DeleteAdAccountAsync(99999);

        // Assert
        Assert.False(result);
    }

    #endregion

    #region Helper Methods

    private void SeedUsers(int count)
    {
        for (int i = 1; i <= count; i++)
        {
            _dbContext.Users.Add(new User
            {
                Id = i,
                Uid = $"U{i:D3}",
                Nickname = $"测试用户{i}",
                Mobile = $"1380013800{i}",
                OpenId = $"openid{i}",
                HeadImg = $"http://test.com/head{i}.jpg",
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            });
        }
        _dbContext.SaveChanges();
    }

    private void SeedUsersWithDates()
    {
        // 今日注册用户
        for (int i = 1; i <= 3; i++)
        {
            _dbContext.Users.Add(new User
            {
                Id = i,
                Uid = $"U{i:D3}",
                Nickname = $"今日用户{i}",
                Mobile = $"1380013800{i}",
                OpenId = $"openid{i}",
                HeadImg = $"http://test.com/head{i}.jpg",
                CreatedAt = DateTime.Today.AddHours(i),
                UpdatedAt = DateTime.Now
            });
        }
        // 昨日注册用户
        for (int i = 4; i <= 6; i++)
        {
            _dbContext.Users.Add(new User
            {
                Id = i,
                Uid = $"U{i:D3}",
                Nickname = $"昨日用户{i}",
                Mobile = $"1380013800{i}",
                OpenId = $"openid{i}",
                HeadImg = $"http://test.com/head{i}.jpg",
                CreatedAt = DateTime.Today.AddDays(-1),
                UpdatedAt = DateTime.Now
            });
        }
        _dbContext.SaveChanges();
    }

    private void SeedOrders(int count)
    {
        for (int i = 1; i <= count; i++)
        {
            _dbContext.Orders.Add(new Order
            {
                UserId = 1,
                OrderNum = $"ORD{i:D5}",
                Price = 100 * i,
                UseMoney = 0,
                UseIntegral = 0,
                UseScore = 0,
                Status = 1,
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now,
                GoodsId = 1,
                GoodsTitle = "商品",
                GoodsPrice = 100 * i,
                OrderTotal = 100 * i,
                OrderZheTotal = 100 * i,
                Zhe = 1,
                Num = 1,
                PrizeNum = 1,
                Addtime = (int)DateTimeOffset.Now.ToUnixTimeSeconds()
            });
        }
        _dbContext.SaveChanges();
    }

    private void SeedOrdersWithDates()
    {
        // 今日订单
        for (int i = 1; i <= 2; i++)
        {
            _dbContext.Orders.Add(new Order
            {
                UserId = 1,
                OrderNum = $"TODAY{i:D3}",
                Price = 100 * i,
                UseMoney = 0,
                UseIntegral = 0,
                UseScore = 0,
                Status = 1,
                CreatedAt = DateTime.Today.AddHours(i),
                UpdatedAt = DateTime.Now,
                GoodsId = 1,
                GoodsTitle = "商品",
                GoodsPrice = 100 * i,
                OrderTotal = 100 * i,
                OrderZheTotal = 100 * i,
                Zhe = 1,
                Num = 1,
                PrizeNum = 1,
                Addtime = (int)DateTimeOffset.Now.ToUnixTimeSeconds()
            });
        }
        // 昨日订单
        for (int i = 3; i <= 4; i++)
        {
            _dbContext.Orders.Add(new Order
            {
                UserId = 2,
                OrderNum = $"YEST{i:D3}",
                Price = 200 * i,
                UseMoney = 0,
                UseIntegral = 0,
                UseScore = 0,
                Status = 1,
                CreatedAt = DateTime.Today.AddDays(-1),
                UpdatedAt = DateTime.Now,
                GoodsId = 1,
                GoodsTitle = "商品",
                GoodsPrice = 200 * i,
                OrderTotal = 200 * i,
                OrderZheTotal = 200 * i,
                Zhe = 1,
                Num = 1,
                PrizeNum = 1,
                Addtime = (int)DateTimeOffset.Now.ToUnixTimeSeconds()
            });
        }
        _dbContext.SaveChanges();
    }

    private void SeedAdverts(int count)
    {
        for (int i = 1; i <= count; i++)
        {
            _dbContext.Adverts.Add(new Advert
            {
                ImgUrl = $"http://test.com/ad{i}.jpg",
                Url = $"http://test.com/link{i}",
                Sort = i,
                Type = 1,
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            });
        }
        _dbContext.SaveChanges();
    }

    #endregion
}
