using System.Text.Json;
using FoodsharingSiegen.Server.Service;
using Microsoft.JSInterop;
using Moq;
using Xunit;

namespace FoodsharingSiegen.Tests
{
    public class LocalStorageServiceTests
    {
        [Fact]
        public async Task GetItem_ReturnsDeserializedObject_WhenItemExists()
        {
            // Arrange
            var mockJsRuntime = new Mock<IJSRuntime>();
            var service = new LocalStorageService(mockJsRuntime.Object);
            var expectedObject = new { Name = "Test" };
            var jsonString = JsonSerializer.Serialize(expectedObject);

            mockJsRuntime.Setup(x => x.InvokeAsync<string>("localStorage.getItem", It.IsAny<object[]>()))
                         .ReturnsAsync(jsonString);

            // Act
            var result = await service.GetItem<dynamic>("testKey");

            // Assert
            Assert.NotNull(result);
            mockJsRuntime.Verify(x => x.InvokeAsync<string>("localStorage.getItem", It.Is<object[]>(args => args.Length == 1 && args[0].ToString() == "testKey")), Times.Once);
        }

        [Fact]
        public async Task GetItem_ReturnsDefault_WhenItemDoesNotExist()
        {
            // Arrange
            var mockJsRuntime = new Mock<IJSRuntime>();
            var service = new LocalStorageService(mockJsRuntime.Object);

            mockJsRuntime.Setup(x => x.InvokeAsync<string>("localStorage.getItem", It.IsAny<object[]>()))
                         .ReturnsAsync((string?)null);

            // Act
            var result = await service.GetItem<string>("testKey");

            // Assert
            Assert.Null(result);
        }

        [Fact]
        public async Task SetItem_CallsSetItemInLocalStorage()
        {
            // Arrange
            var mockJsRuntime = new Mock<IJSRuntime>();
            var service = new LocalStorageService(mockJsRuntime.Object);
            var objectToSave = new { Name = "Test" };
            var expectedJson = JsonSerializer.Serialize(objectToSave);

            // Act
            await service.SetItem("testKey", objectToSave);

            // Assert
            // Note: InvokeVoidAsync is an extension method that calls InvokeAsync<IJSVoidResult> under the hood in Blazor.
            mockJsRuntime.Verify(
                x => x.InvokeAsync<It.IsAnyType>(
                    "localStorage.setItem", 
                    It.Is<object[]>(args => args.Length == 2 && args[0].ToString() == "testKey" && args[1].ToString() == expectedJson)),
                Times.Once);
        }

        [Fact]
        public async Task RemoveItem_CallsRemoveItemInLocalStorage()
        {
            // Arrange
            var mockJsRuntime = new Mock<IJSRuntime>();
            var service = new LocalStorageService(mockJsRuntime.Object);

            // Act
            await service.RemoveItem("testKey");

            // Assert
            mockJsRuntime.Verify(
                x => x.InvokeAsync<It.IsAnyType>(
                    "localStorage.removeItem", 
                    It.Is<object[]>(args => args.Length == 1 && args[0].ToString() == "testKey")),
                Times.Once);
        }
    }
}