using ColaFlow.Modules.Mcp.Application.DTOs;
using ColaFlow.Modules.Mcp.Application.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace ColaFlow.API.Controllers;

/// <summary>
/// Controller for managing MCP API Keys
/// Requires JWT authentication (not API Key auth)
/// </summary>
[ApiController]
[Route("api/mcp/keys")]
[Authorize] // Requires JWT authentication
public class McpApiKeysController : ControllerBase
{
    private readonly IMcpApiKeyService _apiKeyService;
    private readonly ILogger<McpApiKeysController> _logger;

    public McpApiKeysController(
        IMcpApiKeyService apiKeyService,
        ILogger<McpApiKeysController> logger)
    {
        _apiKeyService = apiKeyService ?? throw new ArgumentNullException(nameof(apiKeyService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// Create a new API Key
    /// IMPORTANT: The plain API key is only returned once at creation!
    /// </summary>
    /// <remarks>
    /// Sample request:
    ///
    ///     POST /api/mcp/keys
    ///     {
    ///         "name": "Claude Desktop",
    ///         "description": "API key for Claude Desktop integration",
    ///         "read": true,
    ///         "write": true,
    ///         "expirationDays": 90
    ///     }
    ///
    /// Sample response:
    ///
    ///     {
    ///         "id": "...",
    ///         "name": "Claude Desktop",
    ///         "plainKey": "cola_abc123...xyz", // SAVE THIS - shown only once!
    ///         "keyPrefix": "cola_abc123...",
    ///         "expiresAt": "2025-03-01T00:00:00Z",
    ///         "permissions": {
    ///             "read": true,
    ///             "write": true,
    ///             "allowedResources": [],
    ///             "allowedTools": []
    ///         }
    ///     }
    ///
    /// </remarks>
    [HttpPost]
    [ProducesResponseType(typeof(CreateApiKeyResponse), 200)]
    [ProducesResponseType(400)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> CreateApiKey([FromBody] CreateApiKeyRequestDto request)
    {
        try
        {
            // Extract user and tenant from JWT claims
            var userId = Guid.Parse(User.FindFirstValue("user_id")!);
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            var createRequest = new CreateApiKeyRequest
            {
                Name = request.Name,
                Description = request.Description,
                TenantId = tenantId,
                UserId = userId,
                Read = request.Read,
                Write = request.Write,
                AllowedResources = request.AllowedResources,
                AllowedTools = request.AllowedTools,
                IpWhitelist = request.IpWhitelist,
                ExpirationDays = request.ExpirationDays
            };

            var response = await _apiKeyService.CreateAsync(createRequest, HttpContext.RequestAborted);

            _logger.LogInformation("API Key created: {Name} by User {UserId}", request.Name, userId);

            return Ok(response);
        }
        catch (ArgumentException ex)
        {
            _logger.LogWarning(ex, "Invalid API Key creation request");
            return BadRequest(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to create API Key");
            return StatusCode(500, new { message = "Failed to create API Key" });
        }
    }

    /// <summary>
    /// Get all API Keys for the current tenant
    /// </summary>
    [HttpGet]
    [ProducesResponseType(typeof(List<ApiKeyResponse>), 200)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> GetApiKeys()
    {
        try
        {
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            var apiKeys = await _apiKeyService.GetByTenantIdAsync(tenantId, HttpContext.RequestAborted);

            return Ok(apiKeys);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get API Keys");
            return StatusCode(500, new { message = "Failed to get API Keys" });
        }
    }

    /// <summary>
    /// Get API Key by ID
    /// </summary>
    [HttpGet("{id}")]
    [ProducesResponseType(typeof(ApiKeyResponse), 200)]
    [ProducesResponseType(404)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> GetApiKeyById(Guid id)
    {
        try
        {
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            var apiKey = await _apiKeyService.GetByIdAsync(id, tenantId, HttpContext.RequestAborted);
            if (apiKey == null)
            {
                return NotFound(new { message = "API Key not found" });
            }

            return Ok(apiKey);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get API Key {ApiKeyId}", id);
            return StatusCode(500, new { message = "Failed to get API Key" });
        }
    }

    /// <summary>
    /// Update API Key metadata (name, description)
    /// </summary>
    [HttpPatch("{id}/metadata")]
    [ProducesResponseType(typeof(ApiKeyResponse), 200)]
    [ProducesResponseType(404)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> UpdateMetadata(Guid id, [FromBody] UpdateApiKeyMetadataRequest request)
    {
        try
        {
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            var apiKey = await _apiKeyService.UpdateMetadataAsync(id, tenantId, request, HttpContext.RequestAborted);

            _logger.LogInformation("API Key metadata updated: {ApiKeyId}", id);

            return Ok(apiKey);
        }
        catch (InvalidOperationException ex)
        {
            _logger.LogWarning(ex, "API Key not found: {ApiKeyId}", id);
            return NotFound(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update API Key metadata: {ApiKeyId}", id);
            return StatusCode(500, new { message = "Failed to update API Key" });
        }
    }

    /// <summary>
    /// Update API Key permissions
    /// </summary>
    [HttpPatch("{id}/permissions")]
    [ProducesResponseType(typeof(ApiKeyResponse), 200)]
    [ProducesResponseType(404)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> UpdatePermissions(Guid id, [FromBody] UpdateApiKeyPermissionsRequest request)
    {
        try
        {
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            var apiKey = await _apiKeyService.UpdatePermissionsAsync(id, tenantId, request, HttpContext.RequestAborted);

            _logger.LogInformation("API Key permissions updated: {ApiKeyId}", id);

            return Ok(apiKey);
        }
        catch (InvalidOperationException ex)
        {
            _logger.LogWarning(ex, "API Key not found: {ApiKeyId}", id);
            return NotFound(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update API Key permissions: {ApiKeyId}", id);
            return StatusCode(500, new { message = "Failed to update API Key" });
        }
    }

    /// <summary>
    /// Revoke an API Key (soft delete)
    /// </summary>
    [HttpDelete("{id}")]
    [ProducesResponseType(204)]
    [ProducesResponseType(404)]
    [ProducesResponseType(401)]
    public async Task<IActionResult> RevokeApiKey(Guid id)
    {
        try
        {
            var userId = Guid.Parse(User.FindFirstValue("user_id")!);
            var tenantId = Guid.Parse(User.FindFirstValue("tenant_id")!);

            await _apiKeyService.RevokeAsync(id, tenantId, userId, HttpContext.RequestAborted);

            _logger.LogInformation("API Key revoked: {ApiKeyId} by User {UserId}", id, userId);

            return NoContent();
        }
        catch (InvalidOperationException ex)
        {
            _logger.LogWarning(ex, "API Key not found: {ApiKeyId}", id);
            return NotFound(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to revoke API Key: {ApiKeyId}", id);
            return StatusCode(500, new { message = "Failed to revoke API Key" });
        }
    }
}

/// <summary>
/// Request DTO for creating API Key (simplified for API consumers)
/// </summary>
public record CreateApiKeyRequestDto(
    string Name,
    string? Description = null,
    bool Read = true,
    bool Write = false,
    List<string>? AllowedResources = null,
    List<string>? AllowedTools = null,
    List<string>? IpWhitelist = null,
    int ExpirationDays = 90
);
