namespace AAIntegration.SimmonsBank.API.Services;

using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Security.Claims;
using Microsoft.Extensions.Options;
using AAIntegration.SimmonsBank.API.Entities;
using AAIntegration.SimmonsBank.API.Models.Users;
using AAIntegration.SimmonsBank.API.Helpers;
using AAIntegration.SimmonsBank.API.Configs;
using System.Security.Cryptography;

public interface IUserService
{
    string Create(UserCreateRequest model);
    //IEnumerable<User> GetAll();
    //User GetById(int id);
    void Update(string apiKey, UserUpdateRequest model);
    void Delete(string apiKey);
    Dictionary<string, int> GetAllApiKeys();
    //string GetUserApiKey(int id);
    //void InvalidateApiKey(string apiKey);
    //string CreateUserApiKey(int id);
}

public class UserService : IUserService
{
    private DataContext _context;
    private readonly AppSettings _appSettings;

    public UserService(
        DataContext context,
        IOptions<AppSettings> appSettings)
    {
        _context = context;
        _appSettings = appSettings.Value;
    }

    public string Create(UserCreateRequest model)
    {
        User user = new User();
        user.SimmonsBankUsername = model.Username;
        user.SimmonsBankPassword = model.Password;
        user.MFAKey = model.MFAKey;

        // Generate API Key
        user.ApiKey = generateApiKey();

        // save user
        _context.Users.Add(user);
        _context.SaveChanges();

        // Return API Key
        return user.ApiKey;
    }

    /*public IEnumerable<User> GetAll()
    {
        return _context.Users;
    }*/

    /*public User GetById(int id)
    {
        return getUser(id);
    }*/

    public void Update(string apiKey, UserUpdateRequest model)
    {
        var user = getUser(apiKey);

        // User.Username
        if (model.Username != null)
            user.SimmonsBankUsername = model.Username;

        // User.Password
        if (model.Password != null)
            user.SimmonsBankPassword = model.Password;

        // User.MFAKey
        if (model.MFAKey != null)
            user.MFAKey = model.MFAKey;

        _context.Users.Update(user);
        _context.SaveChanges();
    }

    public void Delete(string apiKey)
    {
        var user = getUser(apiKey);
        _context.Users.Remove(user);
        _context.SaveChanges();
    }

    public Dictionary<string, int> GetAllApiKeys()
    {
        return _context.Users
            .Where(u => u.ApiKey != null)
            .ToDictionary(u => u.ApiKey, u => u.Id);
    }

    /*public string GetUserApiKey(int id)
    {
        return this.getUser(id).ApiKey;
    }*/

    /*public void InvalidateApiKey(string apiKey)
    {
        User? user = _context.Users.FirstOrDefault(u => u.ApiKey == apiKey);

        if (user is not null)
            user.ApiKey = null;
    }*/

    // helper methods

    private User getUser(int id)
    {
        var user = _context.Users.Find(id);
        if (user == null) throw new KeyNotFoundException("User not found");
        return user;
    }

    private User getUser(string ApiKey)
    {
        var user = _context.Users
            .Where(u => u.ApiKey == ApiKey)
            .FirstOrDefault();

        if (user == null) throw new KeyNotFoundException("User not found");
        return user;
    }

    private const string _prefix = "CT-";
    private const int _numberOfSecureBytesToGenerate = 32;
    private const int _lengthOfKey = 32;

    private string generateApiKey()
    {
        var bytes = RandomNumberGenerator.GetBytes(_numberOfSecureBytesToGenerate);

        string base64String = Convert.ToBase64String(bytes)
            .Replace("+", "-")
            .Replace("/", "_");
        
        var keyLength = _lengthOfKey - _prefix.Length; 

        return _prefix + base64String[..keyLength];
    }
}