using System.Text;
using System.Text.Json;
using FruitBank.Common.Services;
using Microsoft.JSInterop;

namespace FruitBankHybrid.Web.Client.Services;

/// <summary>
/// WebAssembly implementation of ISecureCredentialService using obfuscated localStorage.
/// Note: WebAssembly has limited cryptography support, so we use Base64 + XOR obfuscation.
/// This prevents casual inspection but is not cryptographically secure.
/// For true security, consider server-side token storage or authentication cookies.
/// </summary>
public sealed class WebSecureCredentialService : ISecureCredentialService
{
    private const string CredentialsKey = "FruitBank_UserCredentials";
    private static readonly TimeSpan ExpirationDuration = TimeSpan.FromDays(2);
    private static readonly byte[] ObfuscationKey = "FruitBank_Secure_v1_2025"u8.ToArray();
    
    private readonly IJSRuntime _jsRuntime;

    public WebSecureCredentialService(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    public async Task SaveCredentialsAsync(string email, string password)
    {
        var data = new SecureCredentialData
        {
            Email = email,
            Password = password,
            ExpiresAtUtc = DateTime.UtcNow.Add(ExpirationDuration)
        };

        var json = JsonSerializer.Serialize(data);
        var obfuscated = Obfuscate(json);
        
        await _jsRuntime.InvokeVoidAsync("localStorage.setItem", CredentialsKey, obfuscated);
    }

    public async Task<StoredCredentials?> GetCredentialsAsync()
    {
        try
        {
            var obfuscated = await _jsRuntime.InvokeAsync<string?>("localStorage.getItem", CredentialsKey);
            if (string.IsNullOrEmpty(obfuscated))
                return null;

            var json = Deobfuscate(obfuscated);
            if (string.IsNullOrEmpty(json))
            {
                await ClearCredentialsAsync();
                return null;
            }

            var data = JsonSerializer.Deserialize<SecureCredentialData>(json);
            if (data == null)
                return null;

            // Check expiration
            if (DateTime.UtcNow > data.ExpiresAtUtc)
            {
                await ClearCredentialsAsync();
                return null;
            }

            return new StoredCredentials(data.Email, data.Password);
        }
        catch
        {
            // If any error occurs (corrupted data, etc.), clear and return null
            await ClearCredentialsAsync();
            return null;
        }
    }

    public async Task ClearCredentialsAsync()
    {
        await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", CredentialsKey);
    }

    private static string Obfuscate(string plainText)
    {
        var plainBytes = Encoding.UTF8.GetBytes(plainText);
        var obfuscatedBytes = new byte[plainBytes.Length];
        
        for (int i = 0; i < plainBytes.Length; i++)
        {
            obfuscatedBytes[i] = (byte)(plainBytes[i] ^ ObfuscationKey[i % ObfuscationKey.Length]);
        }
        
        return Convert.ToBase64String(obfuscatedBytes);
    }

    private static string? Deobfuscate(string obfuscated)
    {
        try
        {
            var obfuscatedBytes = Convert.FromBase64String(obfuscated);
            var plainBytes = new byte[obfuscatedBytes.Length];
            
            for (int i = 0; i < obfuscatedBytes.Length; i++)
            {
                plainBytes[i] = (byte)(obfuscatedBytes[i] ^ ObfuscationKey[i % ObfuscationKey.Length]);
            }
            
            return Encoding.UTF8.GetString(plainBytes);
        }
        catch
        {
            return null;
        }
    }

    private sealed class SecureCredentialData
    {
        public string Email { get; set; } = string.Empty;
        public string Password { get; set; } = string.Empty;
        public DateTime ExpiresAtUtc { get; set; }
    }
}
