using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MembershipService.API.Application.Commands;
using MembershipService.API.Application.Queries;
using Swashbuckle.AspNetCore.Annotations;

namespace MembershipService.API.Controllers;

/// <summary>
/// EN: Controller for managing loyalty stamp cards.
/// VI: Controller de quan ly stamp card loyalty.
/// </summary>
[ApiController]
[Route("api/v{version:apiVersion}/members/stamp-cards")]
[ApiVersion("1.0")]
[Authorize]
[SwaggerTag("Loyalty stamp card management endpoints")]
public class StampCardsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<StampCardsController> _logger;

    public StampCardsController(IMediator mediator, ILogger<StampCardsController> logger)
    {
        _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// EN: Get stamp card status for a member at a shop.
    /// VI: Lay trang thai stamp card cho member tai shop.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get stamp card", Description = "Retrieves stamp card status for a member at a shop")]
    [SwaggerResponse(200, "Stamp card found", typeof(StampCardDto))]
    [SwaggerResponse(404, "Stamp card not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<StampCardDto>> GetStampCard(
        [FromQuery] Guid shopId,
        [FromQuery] Guid memberId,
        CancellationToken cancellationToken)
    {
        var result = await _mediator.Send(new GetStampCardQuery(shopId, memberId), cancellationToken);
        if (result == null)
        {
            return NotFound(new { success = false, error = new { code = "STAMP_CARD_NOT_FOUND", message = "No stamp card found for this member at this shop / Khong tim thay stamp card cho member nay tai shop nay" } });
        }
        return Ok(new { success = true, data = result });
    }

    /// <summary>
    /// EN: Get all stamp cards for a shop (admin view).
    /// VI: Lay tat ca stamp cards cho shop (admin view).
    /// </summary>
    [HttpGet("shop/{shopId:guid}")]
    [SwaggerOperation(Summary = "Get shop stamp cards", Description = "Retrieves all stamp cards for a shop")]
    [SwaggerResponse(200, "Stamp cards retrieved", typeof(GetStampCardsResult))]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<GetStampCardsResult>> GetShopStampCards(
        Guid shopId,
        [FromQuery] int pageIndex = 0,
        [FromQuery] int pageSize = 20,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(
            new GetStampCardsQuery(shopId, pageIndex, pageSize), cancellationToken);
        return Ok(new { success = true, data = result });
    }

    /// <summary>
    /// EN: Create a new stamp card.
    /// VI: Tao stamp card moi.
    /// </summary>
    [HttpPost]
    [SwaggerOperation(Summary = "Create stamp card", Description = "Creates a new loyalty stamp card")]
    [SwaggerResponse(201, "Stamp card created", typeof(CreateStampCardResult))]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(409, "Active stamp card already exists")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<CreateStampCardResult>> Create(
        [FromBody] CreateStampCardCommand command,
        CancellationToken cancellationToken)
    {
        try
        {
            var result = await _mediator.Send(command, cancellationToken);
            return CreatedAtAction(nameof(GetStampCard),
                new { shopId = result.ShopId, memberId = result.MemberId },
                new { success = true, data = result });
        }
        catch (InvalidOperationException ex) when (ex.Message.Contains("already has an active"))
        {
            return Conflict(new { success = false, error = new { code = "STAMP_CARD_EXISTS", message = ex.Message } });
        }
    }

    /// <summary>
    /// EN: Add a stamp after a purchase.
    /// VI: Them stamp sau khi mua hang.
    /// </summary>
    [HttpPost("stamp")]
    [SwaggerOperation(Summary = "Add stamp", Description = "Adds a stamp to a member's active card (auto-creates if none exists)")]
    [SwaggerResponse(200, "Stamp added", typeof(AddStampResult))]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<AddStampResult>> AddStamp(
        [FromBody] AddStampCommand command,
        CancellationToken cancellationToken)
    {
        var result = await _mediator.Send(command, cancellationToken);
        return Ok(new { success = true, data = result });
    }

    /// <summary>
    /// EN: Claim reward on a completed stamp card.
    /// VI: Nhan thuong tren stamp card da hoan thanh.
    /// </summary>
    [HttpPost("{id:guid}/claim")]
    [SwaggerOperation(Summary = "Claim reward", Description = "Claims the reward on a completed stamp card")]
    [SwaggerResponse(200, "Reward claimed", typeof(ClaimRewardResult))]
    [SwaggerResponse(400, "Card not completed or reward already claimed")]
    [SwaggerResponse(404, "Stamp card not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<ClaimRewardResult>> ClaimReward(
        Guid id,
        CancellationToken cancellationToken)
    {
        try
        {
            var result = await _mediator.Send(new ClaimRewardCommand(id), cancellationToken);
            return Ok(new { success = true, data = result });
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { success = false, error = new { code = "STAMP_CARD_NOT_FOUND", message = ex.Message } });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { success = false, error = new { code = "INVALID_OPERATION", message = ex.Message } });
        }
    }

    /// <summary>
    /// EN: Reset a stamp card for a new round (after reward claimed).
    /// VI: Reset stamp card cho vong moi (sau khi da nhan thuong).
    /// </summary>
    [HttpPost("{id:guid}/reset")]
    [SwaggerOperation(Summary = "Reset stamp card", Description = "Resets a stamp card for a new round after reward is claimed")]
    [SwaggerResponse(200, "Stamp card reset", typeof(ResetStampCardResult))]
    [SwaggerResponse(400, "Reward not yet claimed")]
    [SwaggerResponse(404, "Stamp card not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<ResetStampCardResult>> ResetCard(
        Guid id,
        CancellationToken cancellationToken)
    {
        try
        {
            var result = await _mediator.Send(new ResetStampCardCommand(id), cancellationToken);
            return Ok(new { success = true, data = result });
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { success = false, error = new { code = "STAMP_CARD_NOT_FOUND", message = ex.Message } });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { success = false, error = new { code = "INVALID_OPERATION", message = ex.Message } });
        }
    }
}
