using CSharpFunctionalExtensions;
using Wishlist.Data.Entities;
using Wishlist.Data.Services.Interfaces;

namespace Wishlist.Data.Services;

public class WishService : IWishService
{
    private readonly AppDataContext _context;
    private readonly ILogger<WishService> _logger;
    private readonly IWishlistService _wishlistService;

    public WishService(AppDataContext context, ILogger<WishService> logger, IWishlistService wishlistService)
    {
        _context = context;
        _logger = logger;
        _wishlistService = wishlistService;
    }

    public async Task<Result<Wish>> Create(Wish entity)
    {
        try
        {
            _logger.LogInformation($"Creating Wish {entity.Id}");
            entity.Created = DateTime.UtcNow;
            entity.LastModified = entity.Created;
            var createdEntity = await _context.Wishes.AddAsync(entity);
            await _context.SaveChangesAsync();
            return createdEntity.Entity;
        }
        catch (Exception e)
        {
            _logger.LogError("An error occurred while creating the Wish. {Entity} - {Error}", entity, e.Message);
            return Result.Failure<Wish>($"An error occurred while creating the Wish. {e}");
        }
    }

    public async Task<Maybe<Wish>> Read(Guid entityId)
    {
        var entity = await _context.Wishes.FindAsync(entityId);
        return entity;
    }

    public async Task<Result<Wish>> Update(Wish entity)
    {
        var oldEntity = await Read(entity.Id);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        entity.LastModified =  DateTime.UtcNow;
        _context.Wishes.Update(entity);
        await _context.SaveChangesAsync();
        return Result.Success(entity);
    }

    public async Task<Result<Wish>> Delete(Guid entityId)
    {
        var entity = await Read(entityId);
        if (entity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var deletedEntity = _context.Wishes.Remove(entity.Value);
        await _context.SaveChangesAsync();
        return Result.Success(deletedEntity.Entity);
    }

    public async Task<Result<List<Wish>>> GetAllWishes(Guid listId)
    {
        var listMaybe = await _wishlistService.Read(listId);
        if (listMaybe.HasNoValue)
        {
            return Result.Failure<List<Wish>>("The given list was not found.");
        }
        return listMaybe.Value.Wishes;
    }

    public async Task<Result<Wish>> UpdateReservedStatus(Guid wishId, User? reservedBy)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.ReserveStatus = new ReserveStatus(reservedBy);
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdatePriceInfo(Guid wishId, PriceInfo priceInfo)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.Price = priceInfo;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdateImage(Guid wishId, Uri imageUri)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.ImageUrl = imageUri;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdateStore(Guid wishId, Uri storeUri)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.StoreLink = storeUri;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdateName(Guid wishId, string name)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.Name = name;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdateDescription(Guid wishId, string description)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.Description = description;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdateVisibility(Guid wishId, bool isVisible)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        wish.IsVisible = isVisible;
        return await Update(wish);
    }

    public async Task<Result<Wish>> UpdatePrice(Guid wishId, double price)
    {
        var oldEntity = await Read(wishId);
        if (oldEntity.HasNoValue)
        {
            return Result.Failure<Wish>("The given entity was not found.");
        }
        var wish = oldEntity.Value;
        var oldPrice = wish.Price;
        oldPrice.Price = price;
        wish.Price = oldPrice;
        return await Update(wish);
    }
}