using ColaFlow.Modules.Identity.Application.Commands.InviteUser;
using ColaFlow.Modules.Identity.Application.Commands.CancelInvitation;
using ColaFlow.Modules.Identity.Application.Queries.GetPendingInvitations;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ColaFlow.API.Controllers;

/// <summary>
/// Controller for managing tenant invitations
/// </summary>
[ApiController]
[Route("api/tenants/{tenantId}/invitations")]
[Authorize]
public class TenantInvitationsController(IMediator mediator) : ControllerBase
{
    /// <summary>
    /// Invite a user to the tenant by email
    /// </summary>
    [HttpPost]
    [Authorize(Policy = "RequireTenantAdmin")]
    public async Task<IActionResult> InviteUser(
        [FromRoute] Guid tenantId,
        [FromBody] InviteUserRequest request)
    {
        // SECURITY: Validate user belongs to target tenant
        var userTenantIdClaim = User.FindFirst("tenant_id")?.Value;
        if (userTenantIdClaim == null)
            return Unauthorized(new { error = "Tenant information not found in token" });

        var userTenantId = Guid.Parse(userTenantIdClaim);
        if (userTenantId != tenantId)
            return StatusCode(403, new { error = "Access denied: You can only invite users to your own tenant" });

        // Extract current user ID from claims
        var currentUserIdClaim = User.FindFirst("user_id")?.Value;
        if (currentUserIdClaim == null)
            return Unauthorized(new { error = "User ID not found in token" });

        var currentUserId = Guid.Parse(currentUserIdClaim);

        // Build base URL for invitation link
        var baseUrl = $"{Request.Scheme}://{Request.Host}";

        var command = new InviteUserCommand(
            tenantId,
            request.Email,
            request.Role,
            currentUserId,
            baseUrl);

        try
        {
            var invitationId = await mediator.Send(command);

            return Ok(new
            {
                invitationId,
                message = "Invitation sent successfully",
                email = request.Email,
                role = request.Role
            });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Get all pending invitations for the tenant
    /// </summary>
    [HttpGet]
    [Authorize(Policy = "RequireTenantAdmin")]
    public async Task<IActionResult> GetPendingInvitations([FromRoute] Guid tenantId)
    {
        // SECURITY: Validate user belongs to target tenant
        var userTenantIdClaim = User.FindFirst("tenant_id")?.Value;
        if (userTenantIdClaim == null)
            return Unauthorized(new { error = "Tenant information not found in token" });

        var userTenantId = Guid.Parse(userTenantIdClaim);
        if (userTenantId != tenantId)
            return StatusCode(403, new { error = "Access denied: You can only view invitations for your own tenant" });

        var query = new GetPendingInvitationsQuery(tenantId);
        var invitations = await mediator.Send(query);

        return Ok(invitations);
    }

    /// <summary>
    /// Cancel a pending invitation
    /// </summary>
    [HttpDelete("{invitationId}")]
    [Authorize(Policy = "RequireTenantOwner")]
    public async Task<IActionResult> CancelInvitation(
        [FromRoute] Guid tenantId,
        [FromRoute] Guid invitationId)
    {
        // SECURITY: Validate user belongs to target tenant
        var userTenantIdClaim = User.FindFirst("tenant_id")?.Value;
        if (userTenantIdClaim == null)
            return Unauthorized(new { error = "Tenant information not found in token" });

        var userTenantId = Guid.Parse(userTenantIdClaim);
        if (userTenantId != tenantId)
            return StatusCode(403, new { error = "Access denied: You can only cancel invitations in your own tenant" });

        // Extract current user ID from claims
        var currentUserIdClaim = User.FindFirst("user_id")?.Value;
        if (currentUserIdClaim == null)
            return Unauthorized(new { error = "User ID not found in token" });

        var currentUserId = Guid.Parse(currentUserIdClaim);

        var command = new CancelInvitationCommand(invitationId, tenantId, currentUserId);

        try
        {
            await mediator.Send(command);
            return Ok(new { message = "Invitation cancelled successfully" });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }
}

/// <summary>
/// Request to invite a user to a tenant
/// </summary>
public record InviteUserRequest(string Email, string Role);
