namespace WalletService.API.Controllers.Admin;

using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using WalletService.API.Application.Commands;
using WalletService.API.Application.Queries;
using WalletService.API.Controllers;
using WalletService.Domain.AggregatesModel.PointAccountAggregate;

/// <summary>
/// EN: Admin controller for points management operations (Backoffice).
/// VI: Controller Admin cho các thao tác quản lý điểm (Backoffice).
/// </summary>
[ApiController]
[Route("api/v1/admin/points")]
[Authorize(Roles = "Admin,SuperAdmin")]
[SwaggerTag("Admin Points Management / Quản lý điểm Admin")]
public class AdminPointsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly IPointAccountRepository _pointAccountRepository;
    private readonly ILogger<AdminPointsController> _logger;

    public AdminPointsController(
        IMediator mediator,
        IPointAccountRepository pointAccountRepository,
        ILogger<AdminPointsController> logger)
    {
        _mediator = mediator;
        _pointAccountRepository = pointAccountRepository;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get all point accounts with pagination.
    /// VI: Lấy tất cả tài khoản điểm với phân trang.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get all point accounts", Description = "Get all point accounts with pagination (Admin only)")]
    [SwaggerResponse(200, "Success", typeof(ApiResponse<AdminPointAccountsListDto>))]
    public async Task<IActionResult> GetAllPointAccounts(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] long? minPoints = null,
        [FromQuery] long? maxPoints = null)
    {
        var query = new GetAllPointAccountsQuery(page, pageSize, minPoints, maxPoints);
        var result = await _mediator.Send(query);

        return Ok(new ApiResponse<AdminPointAccountsListDto>(true, "Success", result));
    }

    /// <summary>
    /// EN: Get point account details by ID.
    /// VI: Lấy chi tiết tài khoản điểm theo ID.
    /// </summary>
    [HttpGet("{accountId:guid}")]
    [SwaggerOperation(Summary = "Get point account by ID", Description = "Get point account details by ID (Admin only)")]
    [SwaggerResponse(200, "Success", typeof(ApiResponse<AdminPointAccountDetailDto>))]
    [SwaggerResponse(404, "Point account not found")]
    public async Task<IActionResult> GetPointAccountById(Guid accountId)
    {
        var query = new GetPointAccountByIdQuery(accountId);
        var result = await _mediator.Send(query);

        if (result == null)
            return NotFound(new ApiResponse<object>(false, "Point account not found"));

        return Ok(new ApiResponse<AdminPointAccountDetailDto>(true, "Success", result));
    }

    /// <summary>
    /// EN: Adjust points (add or subtract).
    /// VI: Điều chỉnh điểm (cộng hoặc trừ).
    /// </summary>
    [HttpPost("{accountId:guid}/adjust")]
    [SwaggerOperation(Summary = "Adjust points", Description = "Adjust points for a user account (Admin only)")]
    [SwaggerResponse(200, "Points adjusted")]
    [SwaggerResponse(400, "Invalid adjustment")]
    [SwaggerResponse(404, "Point account not found")]
    public async Task<IActionResult> AdjustPoints(Guid accountId, [FromBody] AdminAdjustPointsRequest request)
    {
        var command = new AdminAdjustPointsCommand(
            accountId,
            request.Points,
            request.Reason,
            GetAdminId());

        var result = await _mediator.Send(command);

        _logger.LogInformation(
            "Admin {AdminId} adjusted points for account {AccountId} by {Points}. Reason: {Reason}",
            GetAdminId(), accountId, request.Points, request.Reason);

        return Ok(new ApiResponse<AdminAdjustPointsResult>(true, "Points adjusted successfully", result));
    }

    /// <summary>
    /// EN: Grant bonus points to user.
    /// VI: Tặng điểm thưởng cho người dùng.
    /// </summary>
    [HttpPost("{accountId:guid}/bonus")]
    [SwaggerOperation(Summary = "Grant bonus points", Description = "Grant bonus points to user (Admin only)")]
    [SwaggerResponse(200, "Bonus points granted")]
    [SwaggerResponse(404, "Point account not found")]
    public async Task<IActionResult> GrantBonusPoints(Guid accountId, [FromBody] AdminGrantBonusRequest request)
    {
        var command = new AdminGrantBonusCommand(
            accountId,
            request.Points,
            request.Reason,
            request.ExpiryMonths,
            GetAdminId());

        var result = await _mediator.Send(command);

        _logger.LogInformation(
            "Admin {AdminId} granted {Points} bonus points to account {AccountId}. Reason: {Reason}",
            GetAdminId(), request.Points, accountId, request.Reason);

        return Ok(new ApiResponse<AdminGrantBonusResult>(true, "Bonus points granted successfully", result));
    }

    /// <summary>
    /// EN: Get points statistics.
    /// VI: Lấy thống kê điểm.
    /// </summary>
    [HttpGet("statistics")]
    [SwaggerOperation(Summary = "Get statistics", Description = "Get points statistics (Admin only)")]
    [SwaggerResponse(200, "Success", typeof(ApiResponse<PointsStatisticsDto>))]
    public async Task<IActionResult> GetStatistics()
    {
        var query = new GetPointsStatisticsQuery();
        var result = await _mediator.Send(query);

        return Ok(new ApiResponse<PointsStatisticsDto>(true, "Success", result));
    }

    /// <summary>
    /// EN: Search point accounts by user ID.
    /// VI: Tìm kiếm tài khoản điểm theo user ID.
    /// </summary>
    [HttpGet("search")]
    [SwaggerOperation(Summary = "Search point accounts", Description = "Search point accounts by user ID (Admin only)")]
    [SwaggerResponse(200, "Success")]
    public async Task<IActionResult> SearchPointAccounts([FromQuery] Guid? userId = null)
    {
        var query = new SearchPointAccountsQuery(userId);
        var result = await _mediator.Send(query);

        return Ok(new ApiResponse<List<AdminPointAccountDetailDto>>(true, "Success", result));
    }

    private Guid GetAdminId()
    {
        var userIdClaim = User.FindFirst("sub")?.Value ?? User.FindFirst("id")?.Value;
        return Guid.TryParse(userIdClaim, out var userId) ? userId : Guid.Empty;
    }
}

#region Admin Request/Response DTOs

public record AdminAdjustPointsRequest(long Points, string Reason);
public record AdminGrantBonusRequest(long Points, string Reason, int? ExpiryMonths = 12);

#endregion
