using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using TrackQrApi.Data;
using TrackQrApi.Features.Auth.Common;
using TrackQrApi.Models;

namespace TrackQrApi.Features.ApiKeys.Endpoints;

public class CreateApiKeyRequest
{
    public Guid WorkspaceId { get; set; }
    public required string Name { get; set; }
    public DateTime? ExpiresAt { get; set; }
    public List<string>? Scopes { get; set; }
}

public class CreateApiKeyResponse
{
    public required Guid Id { get; set; }
    public required string Name { get; set; }
    public required string Key { get; set; } // Only returned once on creation!
    public required string KeyPrefix { get; set; }
    public List<string>? Scopes { get; set; }
    public DateTime? ExpiresAt { get; set; }
    public DateTime CreatedAt { get; set; }
}

public class CreateApiKeyEndpoint(AppDbContext db)
    : Endpoint<CreateApiKeyRequest, CreateApiKeyResponse>
{
    public override void Configure()
    {
        Post("/workspaces/{WorkspaceId}/TrackQrApi-keys");
    }

    public override async Task HandleAsync(CreateApiKeyRequest req, CancellationToken ct)
    {
        var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);

        // Verify workspace ownership
        var workspace = await db.Workspaces
            .FirstOrDefaultAsync(w => w.Id == req.WorkspaceId && w.OwnerUserId == userId, ct);

        if (workspace is null)
        {
            await HttpContext.Response.SendAsync(new MessageResponse("Workspace not found"), 404, cancellation: ct);
            return;
        }

        // Check API key limit (max 10 per workspace)
        var existingCount = await db.ApiKeys.CountAsync(k => k.WorkspaceId == req.WorkspaceId && k.IsActive, ct);
        if (existingCount >= 10)
        {
            await HttpContext.Response.SendAsync(new MessageResponse("Maximum 10 API keys per workspace"), 400,
                cancellation: ct);
            return;
        }

        // Generate secure key: trk_<32 random bytes as base64url>
        var randomBytes = RandomNumberGenerator.GetBytes(32);
        var keyValue = "trk_" + Convert.ToBase64String(randomBytes).Replace("+", "-").Replace("/", "_").TrimEnd('=');
        var keyHash = ComputeSha256Hash(keyValue);
        var keyPrefix = keyValue[..12] + "...";

        var apiKey = new ApiKey
        {
            Id = Guid.NewGuid(),
            WorkspaceId = req.WorkspaceId,
            Name = req.Name,
            KeyHash = keyHash,
            KeyPrefix = keyPrefix,
            Scopes = req.Scopes,
            ExpiresAt = req.ExpiresAt,
            CreatedAt = DateTime.UtcNow,
            IsActive = true
        };

        db.ApiKeys.Add(apiKey);
        await db.SaveChangesAsync(ct);

        var response = new CreateApiKeyResponse
        {
            Id = apiKey.Id,
            Name = apiKey.Name,
            Key = keyValue, // Only returned once!
            KeyPrefix = keyPrefix,
            Scopes = apiKey.Scopes,
            ExpiresAt = apiKey.ExpiresAt,
            CreatedAt = apiKey.CreatedAt
        };

        await HttpContext.Response.SendAsync(response, 201, cancellation: ct);
    }

    private static string ComputeSha256Hash(string input)
    {
        var bytes = Encoding.UTF8.GetBytes(input);
        var hash = SHA256.HashData(bytes);
        return Convert.ToHexString(hash).ToLower();
    }
}