using System.Security.Cryptography;
using Nalu.Web.Data.Models;
using Nalu.Web.Data.Repositories;

namespace Nalu.Web.Services;

public class UserService(UserRepository users, ApiKeyRepository apiKeys, ILogger<UserService> logger)
{
    public record LoginResult(NaluUser User, ApiKey ApiKey, bool IsNew);

    public async Task<LoginResult> LoginOrCreateAsync(
        string provider, string providerId,
        string email, string? name, string? pictureUrl,
        CancellationToken ct = default)
    {
        // Find existing user
        var user = await users.FindByProviderAsync(provider, providerId, ct);

        if (user is not null)
        {
            // Update profile on each login
            user.Name = name;
            user.PictureUrl = pictureUrl;
            user.LastLoginAt = DateTime.UtcNow;
            await users.UpsertAsync(user, ct);

            var existingKey = (await apiKeys.GetByUserAsync(user.Id, ct)).FirstOrDefault();
            if (existingKey is not null)
                return new LoginResult(user, existingKey, IsNew: false);

            // User exists but somehow has no key — create one
            var key = await CreateApiKeyAsync(user, ct);
            return new LoginResult(user, key, IsNew: false);
        }

        // New user
        user = new NaluUser
        {
            Email = email,
            Name = name,
            Provider = provider,
            ProviderId = providerId,
            PictureUrl = pictureUrl,
            Plan = "free",
        };
        await users.UpsertAsync(user, ct);

        // Re-fetch to get DB-assigned id after upsert
        user = await users.FindByProviderAsync(provider, providerId, ct) ?? user;

        var newKey = await CreateApiKeyAsync(user, ct);
        logger.LogInformation("New user created: {Email} via {Provider}", email, provider);

        return new LoginResult(user, newKey, IsNew: true);
    }

    private async Task<ApiKey> CreateApiKeyAsync(NaluUser user, CancellationToken ct)
    {
        var rawKey = $"nalu-{GenerateRandomBase62(32)}";
        var apiKey = new ApiKey
        {
            Key = rawKey,
            Plan = user.Plan,
            Owner = user.Email,
            UserId = user.Id,
            Label = "Default",
        };
        await apiKeys.InsertAsync(apiKey, ct);
        return apiKey;
    }

    private static string GenerateRandomBase62(int length)
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var bytes = RandomNumberGenerator.GetBytes(length);
        return new string(bytes.Select(b => chars[b % chars.Length]).ToArray());
    }
}
