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

namespace BookmarkApi.Core.Services;

/// <summary>
/// 设备服务实现
/// </summary>
public class DeviceService : IDeviceService
{
    private readonly IFreeSql _freeSql;

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

    /// <inheritdoc />
    public async Task<List<DeviceDto>> GetUserDevicesAsync(Guid userId)
    {
        var devices = await _freeSql.Select<Device>()
            .Where(d => d.UserId == userId)
            .OrderByDescending(d => d.LastActiveAt)
            .ToListAsync();

        return devices.Select(MapToDto).ToList();
    }

    /// <inheritdoc />
    public async Task<DeviceDto?> GetDeviceAsync(Guid deviceId)
    {
        var device = await _freeSql.Select<Device>()
            .Where(d => d.Id == deviceId)
            .FirstAsync();

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

    /// <inheritdoc />
    public async Task<DeviceDto?> UpdateDeviceNameAsync(Guid deviceId, Guid userId, string deviceName)
    {
        var device = await _freeSql.Select<Device>()
            .Where(d => d.Id == deviceId && d.UserId == userId)
            .FirstAsync();

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

        device.DeviceName = deviceName;

        await _freeSql.Update<Device>()
            .SetSource(device)
            .ExecuteAffrowsAsync();

        return MapToDto(device);
    }

    /// <inheritdoc />
    public async Task<bool> DeleteDeviceAsync(Guid deviceId, Guid userId)
    {
        // 不能删除管理员设备
        var device = await _freeSql.Select<Device>()
            .Where(d => d.Id == deviceId && d.UserId == userId)
            .FirstAsync();

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

        if (device.IsAdmin)
        {
            // 检查是否有其他设备，如果有则需要先转移管理员权限
            var otherDevices = await _freeSql.Select<Device>()
                .Where(d => d.UserId == userId && d.Id != deviceId)
                .AnyAsync();

            if (otherDevices)
            {
                return false; // 需要先转移管理员权限
            }
        }

        // 删除该设备的所有刷新令牌
        await _freeSql.Delete<RefreshToken>()
            .Where(t => t.DeviceId == deviceId)
            .ExecuteAffrowsAsync();

        // 删除设备
        var affectedRows = await _freeSql.Delete<Device>()
            .Where(d => d.Id == deviceId)
            .ExecuteAffrowsAsync();

        return affectedRows > 0;
    }

    /// <inheritdoc />
    public async Task<bool> SetAdminDeviceAsync(Guid deviceId, Guid userId)
    {
        // 检查设备是否属于该用户
        var device = await _freeSql.Select<Device>()
            .Where(d => d.Id == deviceId && d.UserId == userId)
            .FirstAsync();

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

        // 取消其他设备的管理员权限
        await _freeSql.Update<Device>()
            .Set(d => d.IsAdmin, false)
            .Where(d => d.UserId == userId && d.Id != deviceId)
            .ExecuteAffrowsAsync();

        // 设置当前设备为管理员
        await _freeSql.Update<Device>()
            .Set(d => d.IsAdmin, true)
            .Where(d => d.Id == deviceId)
            .ExecuteAffrowsAsync();

        return true;
    }

    /// <inheritdoc />
    public async Task<bool> IsAdminDeviceAsync(Guid deviceId)
    {
        return await _freeSql.Select<Device>()
            .Where(d => d.Id == deviceId && d.IsAdmin)
            .AnyAsync();
    }

    /// <inheritdoc />
    public async Task UpdateLastActiveAsync(Guid deviceId)
    {
        await _freeSql.Update<Device>()
            .Set(d => d.LastActiveAt, DateTime.UtcNow)
            .Where(d => d.Id == deviceId)
            .ExecuteAffrowsAsync();
    }

    private static DeviceDto MapToDto(Device device)
    {
        return new DeviceDto
        {
            Id = device.Id,
            DeviceName = device.DeviceName,
            DeviceType = device.DeviceType,
            IsAdmin = device.IsAdmin,
            CreatedAt = device.CreatedAt,
            LastActiveAt = device.LastActiveAt,
            Status = device.Status
        };
    }
}

