namespace Brizco.Core.MartenServices;

public class BrewService : IBrewService
{
    private readonly IMartenRepositoryWrapper _martenRepositoryWrapper;
    private readonly ICurrentUserService _currentUserService;

    public BrewService(IMartenRepositoryWrapper martenRepositoryWrapper, ICurrentUserService currentUserService)
    {
        _martenRepositoryWrapper = martenRepositoryWrapper;
        _currentUserService = currentUserService;
    }
    public async Task<object> GetLastBrewAsync(string recipeName, CancellationToken cancellationToken = default)
    {
        var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Brews.{recipeName}");
        if (type == null)
            throw new AppException("Recipe not found", ApiResultStatusCode.NotFound);
        if (_currentUserService.ComplexId == null)
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is null");
        if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId))
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong");

        var baseRecipe = await _martenRepositoryWrapper.SetRepository<BaseBrew>()
            .GetEntityAsync(s => s.ComplexId == complexId && s.Name == recipeName, cancellationToken);
        object? recipe;
        if (baseRecipe == null)
            recipe = Activator.CreateInstance(type);
        else
            recipe = JsonConvert.DeserializeObject(baseRecipe.CurrentBrewJson, type) ?? Activator.CreateInstance(type);

        if (recipe == null)
            throw new AppException("Recipe type or base is wrong");

        return recipe;
    }

    public async Task<BaseRecipeLDto> GetBrewAsync(string recipeName, CancellationToken cancellationToken = default)
    {
        var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Brews.{recipeName}");
        if (type == null)
            throw new AppException("Recipe not found", ApiResultStatusCode.NotFound);
        if (_currentUserService.ComplexId == null)
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is null");
        if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId))
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong");

        var baseRecipe = await _martenRepositoryWrapper.SetRepository<BaseBrew>()
            .GetEntityAsync(s => s.ComplexId == complexId && s.Name == recipeName, cancellationToken);
        object? recipe;
        if (baseRecipe == null)
        {
            recipe = Activator.CreateInstance(type);
            baseRecipe = new BaseBrew();
        }
        else
            recipe = JsonConvert.DeserializeObject(baseRecipe.CurrentBrewJson, type) ?? Activator.CreateInstance(type);

        if (recipe == null)
            throw new AppException("Recipe type or base is wrong");

        var pastRecipes = new List<object>();
        foreach (var json in baseRecipe.PastBrewsJson)
        {
            var pastRecipe = JsonConvert.DeserializeObject(json, type) ?? Activator.CreateInstance(type);
            if (pastRecipe != null)
                pastRecipes.Add(pastRecipe);
        }

        var dto = new BaseRecipeLDto
        {
            CurrentRecipe = recipe,
            Name = recipeName,
            PastRecipes = pastRecipes
        };

        return dto;
    }

    public async Task AddBrewAsync(string recipeName, JsonDocument recipeObj, CancellationToken cancellationToken = default)
    {
        var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Brews.{recipeName}");
        if (type == null)
            throw new AppException("Recipe not found", ApiResultStatusCode.NotFound);

        if (_currentUserService.ComplexId == null)
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is null");
        if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId))
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong");

        if (_currentUserService.FullName == null)
            throw new BaseApiException(ApiResultStatusCode.BadRequest, "Full name is null");

        var baseRecipe = await _martenRepositoryWrapper.SetRepository<BaseBrew>()
            .GetEntityAsync(s => s.ComplexId == complexId && s.Name == recipeName, cancellationToken);

        if (baseRecipe == null)
        {
            baseRecipe = new BaseBrew()
            {
                Name = recipeName,
                DotnetType = type.FullName ?? $"Brizco.Domain.MartenEntities.Brews.{recipeName}",
                ComplexId = complexId
            };
            var current = recipeObj.Deserialize(type, new JsonSerializerOptions(JsonSerializerDefaults.Web));
            if (current is IBaseBrew brew)
            {
                brew.LogAt = DateTime.Now;
                brew.LogBy = _currentUserService.FullName;
                baseRecipe.CurrentBrewJson = JsonConvert.SerializeObject(current);
            }
        }
        else
        {
            var current = recipeObj.Deserialize(type,new JsonSerializerOptions(JsonSerializerDefaults.Web));
            if (current is IBaseBrew brew)
            {
                brew.LogAt = DateTime.Now;
                brew.LogBy = _currentUserService.FullName;
                baseRecipe.PastBrewsJson.Insert(0,baseRecipe.CurrentBrewJson);
                baseRecipe.CurrentBrewJson = JsonConvert.SerializeObject(current);
            }
        }

        await _martenRepositoryWrapper.SetRepository<BaseBrew>()
            .AddOrUpdateEntityAsync(baseRecipe, cancellationToken);
    }
}