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 members.
/// VI: Controller để quản lý members.
/// </summary>
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[Authorize]
[SwaggerTag("Member management endpoints")]
public class MembersController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<MembersController> _logger;

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

    /// <summary>
    /// EN: Get member by ID.
    /// VI: Lấy member theo ID.
    /// </summary>
    [HttpGet("{id:guid}")]
    [SwaggerOperation(Summary = "Get member by ID", Description = "Retrieves a member by their unique identifier")]
    [SwaggerResponse(200, "Member found", typeof(MemberDto))]
    [SwaggerResponse(404, "Member not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<MemberDto>> GetById(Guid id)
    {
        var member = await _mediator.Send(new GetMemberByIdQuery(id));
        if (member == null)
        {
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Member {id} not found" } });
        }
        return Ok(new { success = true, data = member });
    }

    /// <summary>
    /// EN: Get current user's member profile.
    /// VI: Lấy profile member của user hiện tại.
    /// </summary>
    [HttpGet("me")]
    [SwaggerOperation(Summary = "Get my member profile", Description = "Retrieves the member profile for the authenticated user")]
    [SwaggerResponse(200, "Member found", typeof(MemberDto))]
    [SwaggerResponse(404, "Member not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<MemberDto>> GetMe()
    {
        var userId = GetCurrentUserId();
        if (userId == null)
        {
            return Unauthorized();
        }

        var member = await _mediator.Send(new GetMemberByIdQuery(userId.Value));
        if (member == null)
        {
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Member profile not found" } });
        }
        return Ok(new { success = true, data = member });
    }

    /// <summary>
    /// EN: Get paginated list of members.
    /// VI: Lấy danh sách members phân trang.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get members list", Description = "Retrieves a paginated list of members")]
    [SwaggerResponse(200, "Members retrieved", typeof(GetMembersResult))]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<GetMembersResult>> GetAll(
        [FromQuery] int pageIndex = 0,
        [FromQuery] int pageSize = 10,
        [FromQuery] string? search = null)
    {
        var result = await _mediator.Send(new GetMembersQuery
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            SearchTerm = search
        });
        return Ok(new { success = true, data = result });
    }

    /// <summary>
    /// EN: Create a new member.
    /// VI: Tạo member mới.
    /// </summary>
    [HttpPost]
    [SwaggerOperation(Summary = "Create member", Description = "Creates a new member profile")]
    [SwaggerResponse(201, "Member created", typeof(CreateMemberResult))]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(409, "Member already exists")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<CreateMemberResult>> Create([FromBody] CreateMemberCommand command)
    {
        try
        {
            var result = await _mediator.Send(command);
            return CreatedAtAction(nameof(GetById), new { id = result.MemberId }, new { success = true, data = result });
        }
        catch (InvalidOperationException ex) when (ex.Message.Contains("already exists"))
        {
            return Conflict(new { success = false, error = new { code = "CONFLICT", message = ex.Message } });
        }
    }

    /// <summary>
    /// EN: Update member profile.
    /// VI: Cập nhật profile member.
    /// </summary>
    [HttpPut("{id:guid}")]
    [SwaggerOperation(Summary = "Update member profile", Description = "Updates a member's profile information")]
    [SwaggerResponse(200, "Member updated", typeof(UpdateMemberProfileResult))]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(404, "Member not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<UpdateMemberProfileResult>> UpdateProfile(
        Guid id,
        [FromBody] UpdateMemberProfileCommand command)
    {
        command.MemberId = id;

        try
        {
            var result = await _mediator.Send(command);
            return Ok(new { success = true, data = result });
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
        }
    }

    /// <summary>
    /// EN: Add experience points to a member.
    /// VI: Thêm điểm kinh nghiệm cho member.
    /// </summary>
    [HttpPost("{id:guid}/experience")]
    [SwaggerOperation(Summary = "Add experience points", Description = "Adds experience points to a member")]
    [SwaggerResponse(200, "Experience added", typeof(AddExperienceResult))]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(404, "Member not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<AddExperienceResult>> AddExperience(
        Guid id,
        [FromBody] AddExperienceCommand command)
    {
        command.MemberId = id;

        try
        {
            var result = await _mediator.Send(command);
            return Ok(new { success = true, data = result });
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = ex.Message } });
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { success = false, error = new { code = "BAD_REQUEST", message = ex.Message } });
        }
    }

    /// <summary>
    /// EN: Get member's level progress.
    /// VI: Lấy tiến độ level của member.
    /// </summary>
    [HttpGet("{id:guid}/progress")]
    [SwaggerOperation(Summary = "Get level progress", Description = "Retrieves member's level progress")]
    [SwaggerResponse(200, "Progress retrieved", typeof(MemberProgressDto))]
    [SwaggerResponse(404, "Member not found")]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<MemberProgressDto>> GetProgress(Guid id)
    {
        var progress = await _mediator.Send(new GetMemberProgressQuery(id));
        if (progress == null)
        {
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = $"Member {id} not found" } });
        }
        return Ok(new { success = true, data = progress });
    }

    /// <summary>
    /// EN: Get member's experience history.
    /// VI: Lấy lịch sử EXP của member.
    /// </summary>
    [HttpGet("{id:guid}/experience")]
    [SwaggerOperation(Summary = "Get experience history", Description = "Retrieves member's experience transaction history")]
    [SwaggerResponse(200, "History retrieved", typeof(ExperienceHistoryResult))]
    [SwaggerResponse(401, "Unauthorized")]
    public async Task<ActionResult<ExperienceHistoryResult>> GetExperienceHistory(
        Guid id,
        [FromQuery] int pageIndex = 0,
        [FromQuery] int pageSize = 20)
    {
        var result = await _mediator.Send(new GetExperienceHistoryQuery(id, pageIndex, pageSize));
        return Ok(new { success = true, data = result });
    }

    private Guid? GetCurrentUserId()
    {
        var userIdClaim = User.FindFirst("sub")?.Value ?? User.FindFirst("id")?.Value;
        if (Guid.TryParse(userIdClaim, out var userId))
        {
            return userId;
        }
        return null;
    }
}
