using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BookmarkApi.Core.Interfaces;
using BookmarkApi.Shared.DTOs;
using BookmarkApi.Shared.Enums;
using BookmarkApi.Data.Entities;

namespace BookmarkApi.Controllers;

/// <summary>
/// 后台管理控制器
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class AdminController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly IDeviceService _deviceService;
    private readonly IBookmarkService _bookmarkService;
    private readonly IFreeSql _freeSql;

    public AdminController(
        IUserService userService,
        IDeviceService deviceService,
        IBookmarkService bookmarkService,
        IFreeSql freeSql)
    {
        _userService = userService;
        _deviceService = deviceService;
        _bookmarkService = bookmarkService;
        _freeSql = freeSql;
    }

    /// <summary>
    /// 获取系统统计数据
    /// </summary>
    [HttpGet("statistics")]
    [ProducesResponseType(typeof(ApiResponse<AdminStatisticsDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<AdminStatisticsDto>>> GetStatistics()
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var now = DateTime.UtcNow;
        var today = now.Date;
        var weekAgo = today.AddDays(-7);
        var monthAgo = today.AddDays(-30);

        var statistics = new AdminStatisticsDto
        {
            TotalUsers = await _freeSql.Select<User>().CountAsync(),
            ActiveUsersLast7Days = await _freeSql.Select<User>()
                .Where(u => u.LastLoginAt != null && u.LastLoginAt >= weekAgo)
                .CountAsync(),
            NewUsersToday = await _freeSql.Select<User>()
                .Where(u => u.CreatedAt >= today)
                .CountAsync(),
            NewUsersThisWeek = await _freeSql.Select<User>()
                .Where(u => u.CreatedAt >= weekAgo)
                .CountAsync(),
            NewUsersThisMonth = await _freeSql.Select<User>()
                .Where(u => u.CreatedAt >= monthAgo)
                .CountAsync(),
            TotalBookmarks = await _freeSql.Select<Bookmark>().CountAsync(),
            TotalDevices = await _freeSql.Select<Device>().CountAsync(),
            DisabledUsers = await _freeSql.Select<User>()
                .Where(u => u.Status == UserStatus.Disabled)
                .CountAsync()
        };

        return Ok(ApiResponse<AdminStatisticsDto>.Ok(statistics));
    }

    /// <summary>
    /// 获取用户列表
    /// </summary>
    [HttpGet("users")]
    [ProducesResponseType(typeof(ApiResponse<PagedResult<AdminUserDto>>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<PagedResult<AdminUserDto>>>> GetUsers(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null,
        [FromQuery] UserStatus? status = null)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var query = _freeSql.Select<User>();

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

        if (status.HasValue)
        {
            query = query.Where(u => u.Status == status.Value);
        }

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

        var userDtos = new List<AdminUserDto>();
        foreach (var user in users)
        {
            var deviceCount = await _freeSql.Select<Device>().Where(d => d.UserId == user.Id).CountAsync();
            var bookmarkCount = await _freeSql.Select<Bookmark>().Where(b => b.UserId == user.Id).CountAsync();

            userDtos.Add(new AdminUserDto
            {
                Id = user.Id,
                Email = user.Email,
                UserName = user.UserName,
                Avatar = user.Avatar,
                Role = user.Role,
                Status = user.Status,
                CreatedAt = user.CreatedAt,
                LastLoginAt = user.LastLoginAt,
                DeviceCount = (int)deviceCount,
                BookmarkCount = (int)bookmarkCount
            });
        }

        var result = PagedResult<AdminUserDto>.Create(userDtos, total, page, pageSize);

        return Ok(ApiResponse<PagedResult<AdminUserDto>>.Ok(result));
    }

    /// <summary>
    /// 获取用户详情
    /// </summary>
    [HttpGet("users/{id:guid}")]
    [ProducesResponseType(typeof(ApiResponse<AdminUserDetailDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<AdminUserDetailDto>>> GetUserDetail(Guid id)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == id)
            .FirstAsync();

        if (user == null)
        {
            return NotFound(ApiResponse<AdminUserDetailDto>.Fail("用户不存在"));
        }

        var devices = await _freeSql.Select<Device>()
            .Where(d => d.UserId == id)
            .OrderByDescending(d => d.LastActiveAt)
            .ToListAsync();

        var bookmarkCount = await _freeSql.Select<Bookmark>().Where(b => b.UserId == id).CountAsync();

        var detail = new AdminUserDetailDto
        {
            Id = user.Id,
            Email = user.Email,
            UserName = user.UserName,
            Avatar = user.Avatar,
            Role = user.Role,
            Status = user.Status,
            CreatedAt = user.CreatedAt,
            LastLoginAt = user.LastLoginAt,
            BookmarkCount = (int)bookmarkCount,
            Devices = devices.Select(d => new DeviceDto
            {
                Id = d.Id,
                DeviceName = d.DeviceName,
                DeviceType = d.DeviceType,
                IsAdmin = d.IsAdmin,
                CreatedAt = d.CreatedAt,
                LastActiveAt = d.LastActiveAt,
                Status = d.Status
            }).ToList()
        };

        return Ok(ApiResponse<AdminUserDetailDto>.Ok(detail));
    }

    /// <summary>
    /// 禁用/启用用户
    /// </summary>
    [HttpPut("users/{id:guid}/status")]
    [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse>> SetUserStatus(Guid id, [FromBody] SetUserStatusRequest request)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        // 不能禁用自己
        var currentUserId = GetCurrentUserId();
        if (currentUserId == id)
        {
            return BadRequest(ApiResponse.Fail("不能禁用自己的账号"));
        }

        var success = await _userService.SetUserStatusAsync(id, request.Disabled);

        if (!success)
        {
            return NotFound(ApiResponse.Fail("用户不存在"));
        }

        return Ok(ApiResponse.Ok(request.Disabled ? "用户已禁用" : "用户已启用"));
    }

    /// <summary>
    /// 重置用户密码
    /// </summary>
    [HttpPost("users/{id:guid}/reset-password")]
    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<string>>> ResetUserPassword(Guid id)
    {
        if (!await IsSuperAdminAsync())
        {
            return Forbid();
        }

        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == id)
            .FirstAsync();

        if (user == null)
        {
            return NotFound(ApiResponse<string>.Fail("用户不存在"));
        }

        // 生成新密码
        var newPassword = GenerateRandomPassword();
        var newHash = BCrypt.Net.BCrypt.HashPassword(newPassword);

        await _freeSql.Update<User>()
            .Set(u => u.PasswordHash, newHash)
            .Where(u => u.Id == id)
            .ExecuteAffrowsAsync();

        return Ok(ApiResponse<string>.Ok(newPassword, "密码已重置"));
    }

    /// <summary>
    /// 获取用户的书签列表
    /// </summary>
    [HttpGet("users/{id:guid}/bookmarks")]
    [ProducesResponseType(typeof(ApiResponse<PagedResult<BookmarkDto>>), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse<PagedResult<BookmarkDto>>>> GetUserBookmarks(
        Guid id,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var query = _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == id);

        if (!string.IsNullOrEmpty(search))
        {
            query = query.Where(b =>
                b.Title.Contains(search) ||
                b.Url.Contains(search));
        }

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

        var bookmarkDtos = bookmarks.Select(b => new BookmarkDto
        {
            Id = b.Id,
            Title = b.Title,
            Url = b.Url,
            Description = b.Description,
            Icon = b.Icon,
            Tags = b.Tags,
            VisitCount = b.VisitCount,
            LastVisitTime = b.LastVisitTime,
            Order = b.Order,
            Visibility = b.Visibility,
            AllowedDevices = b.AllowedDevices,
            CreatedAt = b.CreatedAt,
            UpdatedAt = b.UpdatedAt
        }).ToList();

        var result = PagedResult<BookmarkDto>.Create(bookmarkDtos, total, page, pageSize);

        return Ok(ApiResponse<PagedResult<BookmarkDto>>.Ok(result));
    }

    /// <summary>
    /// 删除用户的书签
    /// </summary>
    [HttpDelete("users/{userId:guid}/bookmarks/{bookmarkId:guid}")]
    [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse>> DeleteUserBookmark(Guid userId, Guid bookmarkId)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var affectedRows = await _freeSql.Delete<Bookmark>()
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .ExecuteAffrowsAsync();

        if (affectedRows == 0)
        {
            return NotFound(ApiResponse.Fail("书签不存在"));
        }

        return Ok(ApiResponse.Ok("书签已删除"));
    }

    /// <summary>
    /// 强制设备下线
    /// </summary>
    [HttpPost("devices/{id:guid}/force-logout")]
    [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse>> ForceDeviceLogout(Guid id)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        // 撤销该设备的所有刷新令牌
        var affectedRows = await _freeSql.Update<RefreshToken>()
            .Set(t => t.IsRevoked, true)
            .Set(t => t.RevokedAt, DateTime.UtcNow)
            .Where(t => t.DeviceId == id && !t.IsRevoked)
            .ExecuteAffrowsAsync();

        return Ok(ApiResponse.Ok($"已撤销 {affectedRows} 个令牌"));
    }

    /// <summary>
    /// 禁用设备
    /// </summary>
    [HttpPut("devices/{id:guid}/status")]
    [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
    public async Task<ActionResult<ApiResponse>> SetDeviceStatus(Guid id, [FromBody] SetDeviceStatusRequest request)
    {
        if (!await IsAdminUserAsync())
        {
            return Forbid();
        }

        var status = request.Disabled ? DeviceStatus.Disabled : DeviceStatus.Normal;

        var affectedRows = await _freeSql.Update<Device>()
            .Set(d => d.Status, status)
            .Where(d => d.Id == id)
            .ExecuteAffrowsAsync();

        if (affectedRows == 0)
        {
            return NotFound(ApiResponse.Fail("设备不存在"));
        }

        // 如果禁用设备，同时撤销其所有令牌
        if (request.Disabled)
        {
            await _freeSql.Update<RefreshToken>()
                .Set(t => t.IsRevoked, true)
                .Set(t => t.RevokedAt, DateTime.UtcNow)
                .Where(t => t.DeviceId == id && !t.IsRevoked)
                .ExecuteAffrowsAsync();
        }

        return Ok(ApiResponse.Ok(request.Disabled ? "设备已禁用" : "设备已启用"));
    }

    private Guid? GetCurrentUserId()
    {
        var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        return Guid.TryParse(userIdClaim, out var userId) ? userId : null;
    }

    private async Task<bool> IsAdminUserAsync()
    {
        var userId = GetCurrentUserId();
        if (userId == null) return false;

        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == userId)
            .FirstAsync();

        return user?.Role >= AdminRole.Admin;
    }

    private async Task<bool> IsSuperAdminAsync()
    {
        var userId = GetCurrentUserId();
        if (userId == null) return false;

        var user = await _freeSql.Select<User>()
            .Where(u => u.Id == userId)
            .FirstAsync();

        return user?.Role == AdminRole.SuperAdmin;
    }

    private static string GenerateRandomPassword(int length = 12)
    {
        const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$%";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }
}

/// <summary>
/// 系统统计数据
/// </summary>
public class AdminStatisticsDto
{
    public long TotalUsers { get; set; }
    public long ActiveUsersLast7Days { get; set; }
    public long NewUsersToday { get; set; }
    public long NewUsersThisWeek { get; set; }
    public long NewUsersThisMonth { get; set; }
    public long TotalBookmarks { get; set; }
    public long TotalDevices { get; set; }
    public long DisabledUsers { get; set; }
}

/// <summary>
/// 管理员用户列表项
/// </summary>
public class AdminUserDto
{
    public Guid Id { get; set; }
    public string Email { get; set; } = string.Empty;
    public string UserName { get; set; } = string.Empty;
    public string? Avatar { get; set; }
    public AdminRole Role { get; set; }
    public UserStatus Status { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? LastLoginAt { get; set; }
    public int DeviceCount { get; set; }
    public int BookmarkCount { get; set; }
}

/// <summary>
/// 管理员用户详情
/// </summary>
public class AdminUserDetailDto : AdminUserDto
{
    public List<DeviceDto> Devices { get; set; } = new();
}

/// <summary>
/// 设置用户状态请求
/// </summary>
public class SetUserStatusRequest
{
    public bool Disabled { get; set; }
}

/// <summary>
/// 设置设备状态请求
/// </summary>
public class SetDeviceStatusRequest
{
    public bool Disabled { get; set; }
}

