using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using IamService.API.Application.Common;
using IamService.API.Application.Commands.Auth;
using IamService.API.Application.Commands.Users;
using IamService.API.Application.Queries.Users;
using IamService.Domain.AggregatesModel.UserAggregate;

namespace IamService.API.Controllers;

/// <summary>
/// EN: Users management controller.
/// VI: Controller quản lý users.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/users")]
[Authorize(AuthenticationSchemes = "Bearer")]
[SwaggerTag("User management endpoints - requires authentication")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<UsersController> _logger;
    private readonly UserManager<ApplicationUser> _userManager;

    public UsersController(
        IMediator mediator,
        ILogger<UsersController> logger,
        UserManager<ApplicationUser> userManager)
    {
        _mediator = mediator;
        _logger = logger;
        _userManager = userManager;
    }

    /// <summary>
    /// EN: Get all users with pagination.
    /// VI: Lấy tất cả users với phân trang.
    /// </summary>
    /// <param name="pageNumber">Page number (1-based)</param>
    /// <param name="pageSize">Number of items per page</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Paginated list of users</returns>
    [HttpGet]
    [Authorize(Policy = "RequireAdmin")]
    [SwaggerOperation(
        Summary = "Get all users",
        Description = "Retrieves a paginated list of all users. Requires Admin role.",
        OperationId = "GetUsers")]
    [SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved users", typeof(ApiResponse<IEnumerable<UserDto>>))]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status403Forbidden, "Insufficient permissions")]
    [ProducesResponseType(typeof(ApiResponse<IEnumerable<UserDto>>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<IActionResult> GetUsers(
        [FromQuery, SwaggerParameter("Page number (1-based)", Required = false)] int pageNumber = 1,
        [FromQuery, SwaggerParameter("Number of items per page", Required = false)] int pageSize = 10,
        CancellationToken cancellationToken = default)
    {
        var query = new GetUsersQuery(pageNumber, pageSize);
        var result = await _mediator.Send(query, cancellationToken);

        return Ok(new ApiResponse<IEnumerable<UserDto>>
        {
            Success = true,
            Data = result.Users.Select(u => new UserDto
            {
                Id = u.Id,
                Email = u.Email ?? string.Empty,
                FirstName = u.FirstName,
                LastName = u.LastName,
                FullName = u.FullName,
                Status = u.Status,
                CreatedAt = u.CreatedAt,
                LastLoginAt = u.LastLoginAt
            }),
            Pagination = new PaginationInfo
            {
                PageNumber = result.PageNumber,
                PageSize = result.PageSize,
                TotalCount = result.TotalCount
            }
        });
    }

    /// <summary>
    /// EN: Get user by ID.
    /// VI: Lấy user theo ID.
    /// </summary>
    /// <param name="id">User ID</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>User information</returns>
    [HttpGet("{id:guid}")]
    [Authorize(Policy = "OwnerOrAdmin")]
    [SwaggerOperation(
        Summary = "Get user by ID",
        Description = "Retrieves a specific user. Users can access their own profile; Admins can access any.",
        OperationId = "GetUserById")]
    [SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved user", typeof(ApiResponse<UserDto>))]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status403Forbidden, "Insufficient permissions")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
    [ProducesResponseType(typeof(ApiResponse<UserDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetUserById(
        [FromRoute, SwaggerParameter("User ID", Required = true)] Guid id,
        CancellationToken cancellationToken = default)
    {
        var query = new GetUserByIdQuery(id);
        var result = await _mediator.Send(query, cancellationToken);

        if (result == null)
        {
            return NotFound(ApiResponse<UserDto>.Fail("USER_NOT_FOUND", $"User with ID {id} not found."));
        }

        return Ok(ApiResponse<UserDto>.Ok(new UserDto
        {
            Id = result.Id,
            Email = result.Email ?? string.Empty,
            FirstName = result.FirstName,
            LastName = result.LastName,
            FullName = result.FullName,
            Status = result.Status?.Name ?? "Unknown",
            CreatedAt = result.CreatedAt,
            LastLoginAt = result.LastLoginAt
        }));
    }

    /// <summary>
    /// EN: Update user information.
    /// VI: Cập nhật thông tin user.
    /// </summary>
    /// <param name="id">User ID to update</param>
    /// <param name="request">Update data</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Updated user information</returns>
    [HttpPut("{id:guid}")]
    [Authorize(Policy = "OwnerOrAdmin")]
    [SwaggerOperation(
        Summary = "Update user",
        Description = "Updates a user's information. Users can update their own profile; Admins can update any.",
        OperationId = "UpdateUser")]
    [SwaggerResponse(StatusCodes.Status200OK, "User updated successfully", typeof(ApiResponse<UserDto>))]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request data")]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status403Forbidden, "Insufficient permissions")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
    [ProducesResponseType(typeof(ApiResponse<UserDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> UpdateUser(
        [FromRoute, SwaggerParameter("User ID to update", Required = true)] Guid id,
        [FromBody, SwaggerRequestBody("User update data", Required = true)] UpdateUserRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new UpdateUserCommand(id, request.FirstName, request.LastName);

        try
        {
            var result = await _mediator.Send(command, cancellationToken);

            return Ok(ApiResponse<UserDto>.Ok(new UserDto
            {
                Id = result.UserId,
                Email = result.Email,
                FirstName = result.FirstName,
                LastName = result.LastName,
                FullName = result.FullName
            }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<UserDto>.Fail("USER_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Admin reset password for a user (no current password required).
    /// VI: Admin reset mật khẩu cho user (không cần mật khẩu hiện tại).
    /// </summary>
    [HttpPost("{id:guid}/reset-password")]
    [AllowAnonymous]
    [SwaggerOperation(Summary = "Admin reset password", Description = "Resets a user's password without requiring current password. Internal BFF-only endpoint.")]
    [ProducesResponseType(typeof(ChangePasswordCommandResult), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> AdminResetPassword(
        [FromRoute] Guid id,
        [FromBody] AdminResetPasswordRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new AdminResetPasswordCommand(id, request.NewPassword);
        var result = await _mediator.Send(command, cancellationToken);
        if (!result.Success)
            return BadRequest(new { success = false, message = result.Message });
        return Ok(new { success = true, message = result.Message });
    }

    /// <summary>
    /// EN: Delete (deactivate) a user.
    /// VI: Xóa (vô hiệu hóa) user.
    /// </summary>
    /// <param name="id">User ID to delete</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Deletion result</returns>
    [HttpDelete("{id:guid}")]
    [Authorize(Policy = "RequireAdmin")]
    [SwaggerOperation(
        Summary = "Delete user",
        Description = "Soft deletes (deactivates) a user. Requires Admin role.",
        OperationId = "DeleteUser")]
    [SwaggerResponse(StatusCodes.Status200OK, "User deleted successfully")]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status403Forbidden, "Insufficient permissions")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
    [ProducesResponseType(typeof(ApiResponse<DeleteUserResult>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> DeleteUser(
        [FromRoute, SwaggerParameter("User ID to delete", Required = true)] Guid id,
        CancellationToken cancellationToken = default)
    {
        var command = new DeleteUserCommand(id);

        try
        {
            var result = await _mediator.Send(command, cancellationToken);
            return Ok(ApiResponse<DeleteUserResult>.Ok(new DeleteUserResult
            {
                Success = result.Success,
                Message = result.Message
            }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<DeleteUserResult>.Fail("USER_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Get current user info.
    /// VI: Lấy thông tin user hiện tại.
    /// </summary>
    /// <returns>Current user information</returns>
    [HttpGet("me")]
    [SwaggerOperation(
        Summary = "Get current user",
        Description = "Retrieves information about the currently authenticated user.",
        OperationId = "GetCurrentUser")]
    [SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved current user", typeof(ApiResponse<CurrentUserDto>))]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [ProducesResponseType(typeof(ApiResponse<CurrentUserDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public IActionResult GetCurrentUser()
    {
        var userId = User.FindFirst("sub")?.Value;
        var email = User.FindFirst("email")?.Value;
        var name = User.FindFirst("name")?.Value;
        var roles = User.FindAll("role").Select(c => c.Value);

        return Ok(ApiResponse<CurrentUserDto>.Ok(new CurrentUserDto
        {
            Id = userId ?? string.Empty,
            Email = email,
            Name = name,
            Roles = roles
        }));
    }

    /// <summary>
    /// EN: Get user roles by user ID.
    /// VI: Lấy danh sách roles của user theo ID.
    /// </summary>
    /// <param name="id">User ID</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>List of user roles</returns>
    [HttpGet("{id:guid}/roles")]
    [SwaggerOperation(
        Summary = "Get user roles",
        Description = "Retrieves all roles assigned to a specific user.",
        OperationId = "GetUserRoles")]
    [SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved user roles", typeof(ApiResponse<UserRolesDto>))]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
    [ProducesResponseType(typeof(ApiResponse<UserRolesDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetUserRoles(
        [FromRoute, SwaggerParameter("User ID", Required = true)] Guid id,
        CancellationToken cancellationToken = default)
    {
        var user = await _userManager.FindByIdAsync(id.ToString());
        if (user == null)
        {
            return NotFound(ApiResponse<UserRolesDto>.Fail("USER_NOT_FOUND", $"User with ID {id} not found."));
        }

        var roles = await _userManager.GetRolesAsync(user);

        return Ok(ApiResponse<UserRolesDto>.Ok(new UserRolesDto
        {
            UserId = id.ToString(),
            Roles = roles
        }));
    }

    /// <summary>
    /// EN: Get user permissions by user ID.
    /// VI: Lấy danh sách permissions của user theo ID.
    /// </summary>
    /// <param name="id">User ID</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>List of user permissions</returns>
    [HttpGet("{id:guid}/permissions")]
    [SwaggerOperation(
        Summary = "Get user permissions",
        Description = "Retrieves all permissions for a specific user (derived from roles).",
        OperationId = "GetUserPermissions")]
    [SwaggerResponse(StatusCodes.Status200OK, "Successfully retrieved user permissions", typeof(ApiResponse<UserPermissionsDto>))]
    [SwaggerResponse(StatusCodes.Status401Unauthorized, "Authentication required")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "User not found")]
    [ProducesResponseType(typeof(ApiResponse<UserPermissionsDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetUserPermissions(
        [FromRoute, SwaggerParameter("User ID", Required = true)] Guid id,
        CancellationToken cancellationToken = default)
    {
        var user = await _userManager.FindByIdAsync(id.ToString());
        if (user == null)
        {
            return NotFound(ApiResponse<UserPermissionsDto>.Fail("USER_NOT_FOUND", $"User with ID {id} not found."));
        }

        var roles = await _userManager.GetRolesAsync(user);
        var claims = await _userManager.GetClaimsAsync(user);
        
        // EN: Extract permissions from claims
        // VI: Lấy permissions từ claims
        var permissions = claims
            .Where(c => c.Type == "permission")
            .Select(c => c.Value)
            .ToList();

        return Ok(ApiResponse<UserPermissionsDto>.Ok(new UserPermissionsDto
        {
            UserId = id.ToString(),
            Roles = roles,
            Permissions = permissions
        }));
    }
}

/// <summary>
/// EN: Request body for updating user.
/// VI: Request body để cập nhật user.
/// </summary>
public class UpdateUserRequest
{
    /// <summary>
    /// EN: New first name.
    /// VI: Tên mới.
    /// </summary>
    /// <example>John</example>
    public string? FirstName { get; set; }

    /// <summary>
    /// EN: New last name.
    /// VI: Họ mới.
    /// </summary>
    /// <example>Doe</example>
    public string? LastName { get; set; }
}

/// <summary>
/// EN: Result of delete user operation.
/// VI: Kết quả của thao tác xóa user.
/// </summary>
public class DeleteUserResult
{
    /// <summary>
    /// EN: Whether the operation was successful.
    /// VI: Thao tác có thành công không.
    /// </summary>
    public bool Success { get; set; }

    /// <summary>
    /// EN: Result message.
    /// VI: Thông điệp kết quả.
    /// </summary>
    public string Message { get; set; } = string.Empty;
}

/// <summary>
/// EN: User roles response DTO.
/// VI: DTO response cho danh sách roles của user.
/// </summary>
public class UserRolesDto
{
    /// <summary>
    /// EN: User ID.
    /// VI: ID của user.
    /// </summary>
    public string UserId { get; set; } = string.Empty;

    /// <summary>
    /// EN: List of role names assigned to the user.
    /// VI: Danh sách tên roles được gán cho user.
    /// </summary>
    public IEnumerable<string> Roles { get; set; } = Enumerable.Empty<string>();
}

/// <summary>
/// EN: User permissions response DTO.
/// VI: DTO response cho danh sách permissions của user.
/// </summary>
public class UserPermissionsDto
{
    /// <summary>
    /// EN: User ID.
    /// VI: ID của user.
    /// </summary>
    public string UserId { get; set; } = string.Empty;

    /// <summary>
    /// EN: List of role names assigned to the user.
    /// VI: Danh sách tên roles được gán cho user.
    /// </summary>
    public IEnumerable<string> Roles { get; set; } = Enumerable.Empty<string>();

    /// <summary>
    /// EN: List of permission names assigned to the user.
    /// VI: Danh sách tên permissions được gán cho user.
    /// </summary>
    public IEnumerable<string> Permissions { get; set; } = Enumerable.Empty<string>();
}

/// <summary>
/// EN: Request body for admin password reset.
/// VI: Request body cho admin reset mật khẩu.
/// </summary>
public class AdminResetPasswordRequest
{
    public string NewPassword { get; set; } = string.Empty;
}
