using OpenWarehouse.warehouse.api.Common.Producer;

namespace OpenWarehouse.warehouse.api.Common.Item;

public class ItemManager(ApplicationDbContext context, IProducerManager producerManager) : IItemManager
{
    public async Task<Data.Item?> FindItemByIdAsync(string id)
    {
        var result = await context.Items
            .Include(item => item.ItemCategoryTags)
            .Include(item => item.ItemClaims)
            .FirstOrDefaultAsync(item => item.Id != null && item.Id.Equals(id));

        return result;
    }

    public async Task<Data.Item?> FindItemByNameAsync(string producerName, string itemName)
    {
        var producer = await producerManager.FindProducerByName(producerName);
        if (producer != null)
        {
            return await FindItemByNameAsync(producer, itemName);
        }

        return null;
    }

    public async Task<Data.Item?> FindItemByNameAsync(Producers producers, string itemName)
    {
        return await context.Items
            .FirstOrDefaultAsync(item => item.Name != null &&
                                         item.Producer == producers && item.Name.Equals(itemName));
    }

    public async Task<ActionResult> CreateAsync(Data.Item item)
    {
        context.Items.Add(item);
        
        ActionResult? res = null;
        
        var error = new Dictionary<string, string>();
        
        try
        {
            res= new ActionResult((await context.SaveChangesAsync()) == 1);
        }
        catch (OperationCanceledException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateConcurrencyException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }

        return res ?? new ActionResult(false, error);
    }

    public async Task<List<Claim>> GetListOfClaims(Data.Item item)
    {
        var result = await context.ItemClaims.Where(claims => claims.Item == item)
            .Select(claims => new Claim(claims.ClaimType ?? "Uknow", claims.ClaimValue ?? "Uknow"))
            .ToListAsync();
        return result;
    }

    public async Task<ActionResult> AddClaim(Data.Item item, Claim claim)
    {
        var newClaim = new ItemClaims(item, claim);
        context.ItemClaims.Add(newClaim);
        
        ActionResult? res = null;
        
        var error = new Dictionary<string, string>();
        
        try
        {
            res= new ActionResult((await context.SaveChangesAsync()) == 1);
        }
        catch (OperationCanceledException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateConcurrencyException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }

        return res ?? new ActionResult(false, error);
    }
    
    public async Task<ActionResult> UpdateClaim(Data.Item item, Claim claim)
    {
        var claimF = await context.ItemClaims
            .FirstOrDefaultAsync(q => q.ClaimType.Equals(claim.Type) && q.ClaimIssuer.Equals(claim.Issuer)
                                                                     && q.Item == item);
        var result = 0;
        
        if (claimF == null)
        {
            result = (await AddClaim(item, claim)).IsSuccess ? 0 : 1;
        }
        else
        {
            claimF.ClaimValue = claim.Value;
            result=  await context.SaveChangesAsync();
        }
        
        
        return result > 0 ? new ActionResult(true, null) : new ActionResult(false, null);
    }

    public async Task<ActionResult> DeleteClaim(Data.Item item, string claimType)
    {
        ActionResult? res = null;
        
        var error = new Dictionary<string, string>();
        int delCount = 0;
        
        try
        {
            delCount = await context.ItemClaims
                .Where(claims => claims.ClaimType != null && claims.Item == item && claims.ClaimType.Equals(claimType))
                .ExecuteDeleteAsync();
        }
        catch (OperationCanceledException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateConcurrencyException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }

        if (res == null)
        {
            res = new ActionResult(delCount == 1, error);
        }
        
        return res;
    }

    public async Task<ActionResult> EditClaim(Data.Item item, string claimType, string newValue)
    {
        ActionResult? res = null;
        
        var error = new Dictionary<string, string>();
        int editCount = 0;
        
        try
        {
            var claim = await context.ItemClaims.FirstOrDefaultAsync(claims =>
                claims.ClaimType != null && claims.Item == item && claims.ClaimType.Equals(claimType));
            if (claim != null) claim.ClaimValue = newValue;
            else
            {
                error["Database"] = $"Claim {item.Name}-{claimType} not found.";
            }

            editCount = await context.SaveChangesAsync();
        }
        catch (OperationCanceledException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateConcurrencyException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }
        catch (DbUpdateException e)
        {
            error[e.Source ?? "Unknown"] = e.Message;
        }

        if (res == null)
        {
            res = new ActionResult(editCount == 1, error);
        }
        
        return res;
    }
}