using BookmarkApi.Core.Interfaces;
using BookmarkApi.Data.Entities;
using BookmarkApi.Shared.DTOs;
using BookmarkApi.Shared.Enums;

namespace BookmarkApi.Core.Services;

/// <summary>
/// 用户服务实现
/// </summary>
public class UserService : IUserService
{
    private readonly IFreeSql _freeSql;

    public UserService(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }

    /// <inheritdoc />
    public async Task<UserDto?> GetByIdAsync(Guid userId)
    {
        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == userId)
            .FirstAsync();

        return user == null ? null : MapToDto(user);
    }

    /// <inheritdoc />
    public async Task<UserDto?> GetByEmailAsync(string email)
    {
        var user = await _freeSql.Select<User>()
            .Where(u => u.Email == email.ToLower())
            .FirstAsync();

        return user == null ? null : MapToDto(user);
    }

    /// <inheritdoc />
    public async Task<UserDto?> UpdateProfileAsync(Guid userId, string? userName, string? avatar)
    {
        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == userId)
            .FirstAsync();

        if (user == null)
        {
            return null;
        }

        if (!string.IsNullOrEmpty(userName))
        {
            user.UserName = userName;
        }

        if (avatar != null)
        {
            user.Avatar = avatar;
        }

        await _freeSql.Update<User>()
            .SetSource(user)
            .ExecuteAffrowsAsync();

        return MapToDto(user);
    }

    /// <inheritdoc />
    public async Task<bool> ChangePasswordAsync(Guid userId, string oldPassword, string newPassword)
    {
        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == userId)
            .FirstAsync();

        if (user == null)
        {
            return false;
        }

        // 验证旧密码
        if (!BCrypt.Net.BCrypt.Verify(oldPassword, user.PasswordHash))
        {
            return false;
        }

        // 更新密码
        var newHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
        await _freeSql.Update<User>()
            .Set(u => u.PasswordHash, newHash)
            .Where(u => u.Id == userId)
            .ExecuteAffrowsAsync();

        return true;
    }

    /// <inheritdoc />
    public async Task<PagedResult<UserDto>> GetAllUsersAsync(int page, int pageSize, string? search)
    {
        var query = _freeSql.Select<User>();

        if (!string.IsNullOrEmpty(search))
        {
            query = query.Where(u => u.Email.Contains(search) || u.UserName.Contains(search));
        }

        var total = await query.CountAsync();
        var users = await query
            .OrderByDescending(u => u.CreatedAt)
            .Page(page, pageSize)
            .ToListAsync();

        return PagedResult<UserDto>.Create(
            users.Select(MapToDto).ToList(),
            total,
            page,
            pageSize
        );
    }

    /// <inheritdoc />
    public async Task<bool> SetUserStatusAsync(Guid userId, bool disabled)
    {
        var status = disabled ? UserStatus.Disabled : UserStatus.Normal;

        var affectedRows = await _freeSql.Update<User>()
            .Set(u => u.Status, status)
            .Where(u => u.Id == userId)
            .ExecuteAffrowsAsync();

        return affectedRows > 0;
    }

    private static UserDto MapToDto(User user)
    {
        return new UserDto
        {
            Id = user.Id,
            Email = user.Email,
            UserName = user.UserName,
            Avatar = user.Avatar,
            Role = user.Role,
            CreatedAt = user.CreatedAt,
            LastLoginAt = user.LastLoginAt
        };
    }
}

