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

namespace IamService.API.Controllers;

/// <summary>
/// EN: Groups management controller.
/// VI: Controller quản lý nhóm.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/groups")]
[Authorize(AuthenticationSchemes = "Bearer")]
[Authorize(Policy = "RequireAdmin")]
[SwaggerTag("Group management endpoints - requires Admin role")]
public class GroupsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<GroupsController> _logger;

    public GroupsController(
        IMediator mediator,
        ILogger<GroupsController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get group by ID.
    /// VI: Lấy nhóm theo ID.
    /// </summary>
    [HttpGet("{id:guid}")]
    [SwaggerOperation(Summary = "Get group by ID", OperationId = "GetGroupById")]
    [SwaggerResponse(StatusCodes.Status200OK, "Group found", typeof(ApiResponse<GroupResponse>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Group not found")]
    public async Task<IActionResult> GetGroupById(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetGroupByIdQuery(id), cancellationToken);

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

        return Ok(ApiResponse<GroupResponse>.Ok(MapToResponse(result)));
    }

    /// <summary>
    /// EN: Get groups by organization.
    /// VI: Lấy nhóm theo tổ chức.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get groups by organization", OperationId = "GetGroupsByOrganization")]
    [SwaggerResponse(StatusCodes.Status200OK, "Groups returned", typeof(ApiResponse<IEnumerable<GroupResponse>>))]
    public async Task<IActionResult> GetGroupsByOrganization(
        [FromQuery] Guid organizationId,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetGroupsByOrganizationQuery(organizationId), cancellationToken);
        return Ok(ApiResponse<IEnumerable<GroupResponse>>.Ok(result.Select(MapToResponse)));
    }

    /// <summary>
    /// EN: Create a new group.
    /// VI: Tạo nhóm mới.
    /// </summary>
    [HttpPost]
    [SwaggerOperation(Summary = "Create group", OperationId = "CreateGroup")]
    [SwaggerResponse(StatusCodes.Status201Created, "Group created", typeof(ApiResponse<GroupResponse>))]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request")]
    public async Task<IActionResult> CreateGroup(
        [FromBody] CreateGroupRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var command = new CreateGroupCommand(request.Name, request.OrganizationId, request.Description);
            var result = await _mediator.Send(command, cancellationToken);

            var response = new GroupResponse
            {
                Id = result.Id,
                Name = result.Name,
                Description = result.Description,
                OrganizationId = result.OrganizationId,
                MemberCount = 0,
                CreatedAt = result.CreatedAt
            };

            return CreatedAtAction(nameof(GetGroupById), new { id = result.Id }, ApiResponse<GroupResponse>.Ok(response));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return BadRequest(ApiResponse<GroupResponse>.Fail("ORG_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Delete (soft) group.
    /// VI: Xóa (mềm) nhóm.
    /// </summary>
    [HttpDelete("{id:guid}")]
    [SwaggerOperation(Summary = "Delete group", OperationId = "DeleteGroup")]
    [SwaggerResponse(StatusCodes.Status200OK, "Group deleted")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Group not found")]
    public async Task<IActionResult> DeleteGroup(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new DeleteGroupCommand(id), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Group deleted successfully." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("GROUP_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Add member to group.
    /// VI: Thêm thành viên vào nhóm.
    /// </summary>
    [HttpPost("{id:guid}/members")]
    [SwaggerOperation(Summary = "Add member to group", OperationId = "AddGroupMember")]
    [SwaggerResponse(StatusCodes.Status200OK, "Member added", typeof(ApiResponse<GroupMemberResponse>))]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "User already member")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Group not found")]
    public async Task<IActionResult> AddMember(
        [FromRoute] Guid id,
        [FromBody] AddGroupMemberRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var command = new AddGroupMemberCommand(id, request.UserId, request.RoleId);
            var result = await _mediator.Send(command, cancellationToken);

            return Ok(ApiResponse<GroupMemberResponse>.Ok(new GroupMemberResponse
            {
                GroupId = result.GroupId,
                UserId = result.UserId,
                Role = result.Role,
                JoinedAt = result.JoinedAt
            }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<GroupMemberResponse>.Fail("GROUP_NOT_FOUND", ex.Message));
        }
        catch (Exception ex) when (ex.Message.Contains("already"))
        {
            return BadRequest(ApiResponse<GroupMemberResponse>.Fail("ALREADY_MEMBER", ex.Message));
        }
    }

    /// <summary>
    /// EN: Remove member from group.
    /// VI: Xóa thành viên khỏi nhóm.
    /// </summary>
    [HttpDelete("{id:guid}/members/{userId:guid}")]
    [SwaggerOperation(Summary = "Remove member from group", OperationId = "RemoveGroupMember")]
    [SwaggerResponse(StatusCodes.Status200OK, "Member removed")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Group or member not found")]
    public async Task<IActionResult> RemoveMember(
        [FromRoute] Guid id,
        [FromRoute] Guid userId,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new RemoveGroupMemberCommand(id, userId), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Member removed successfully." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("NOT_FOUND", ex.Message));
        }
        catch (Exception ex) when (ex.Message.Contains("owner"))
        {
            return BadRequest(ApiResponse<object>.Fail("CANNOT_REMOVE_OWNER", ex.Message));
        }
    }

    private static GroupResponse MapToResponse(GroupDto dto) => new()
    {
        Id = dto.Id,
        Name = dto.Name,
        Description = dto.Description,
        OrganizationId = dto.OrganizationId,
        MemberCount = dto.MemberCount,
        CreatedAt = dto.CreatedAt,
        UpdatedAt = dto.UpdatedAt
    };
}

#region Request/Response Models

public class CreateGroupRequest
{
    public string Name { get; set; } = string.Empty;
    public Guid OrganizationId { get; set; }
    public string? Description { get; set; }
}

public class AddGroupMemberRequest
{
    public Guid UserId { get; set; }
    public int? RoleId { get; set; }  // 1=Member, 2=Admin, 3=Owner
}

public class GroupResponse
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string? Description { get; set; }
    public Guid OrganizationId { get; set; }
    public int MemberCount { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

public class GroupMemberResponse
{
    public Guid GroupId { get; set; }
    public Guid UserId { get; set; }
    public string Role { get; set; } = string.Empty;
    public DateTime JoinedAt { get; set; }
}

#endregion
