namespace OpenWarehouse.warehouse.api.Common.Producer;

public class ProducerManager(ApplicationDbContext context) : IProducerManager
{
    public async Task<Producers?> FindProducerByName(string name)
    {
        return await context.Producers
            .Include(q => q.Claims)
            .AsNoTracking()
            .FirstOrDefaultAsync(producer1 => producer1.Name != null && 
                                              producer1.Name.Equals(name));
    }

    public async Task<Producers?> FindProducerById(Guid? guid)
    {
        return await context.Producers
            .AsNoTracking()
            .FirstOrDefaultAsync(producer1 => producer1.Name != null && 
                                              producer1.Id == guid);
    }

    public async Task<List<Producers>> GetProducerList()
    {
        return await context.Producers.Include(q => q.Claims).AsNoTracking().ToListAsync();
    }

    public async Task<bool> DeleteProducerByName(string name)
    {
        var res = await context.Producers
            .Where(q => q.Name != null && q.Name.Equals(name))
            .Include(q => q.Claims)
            .AsNoTracking()
            .ExecuteDeleteAsync();
        return res > 0;
    }

    public async Task<List<Claim>> GetClaims(Producers producers)
    {
        return await context.ProducerClaims.Where(claims => claims.Producer == producers)
            .Select(claims => new Claim(claims.ClaimType ?? "Unknown", claims.ClaimValue ?? "Unknown"))
            .AsNoTracking()
            .ToListAsync();
    }

    public async Task<ActionResult> CreateAsync(Producers producers)
    {
        context.Producers.Add(producers);
        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> AddClaim(Producers producers, Claim claim)
    {
        context.ProducerClaims.Add(new ProducerClaims(producers, claim));
        
        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> DeleteClaim(Producers producers, string claimType)
    {
        ActionResult? res = null;
        
        var error = new Dictionary<string, string>();
        
        try
        {
            var delRes = await context.ProducerClaims
                .Where(claims => claims.ClaimType != null &&
                                 claims.Producer == producers && claims.ClaimType.Equals(claimType))
                .ExecuteDeleteAsync();
            res= new ActionResult((delRes) == 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;
        }

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

    public async Task<ActionResult> UpdateClaim(Producers producers, Claim claim1)
    {
        var claim = await context.ProducerClaims
            .Where(claims => claims.ClaimType != null &&
                             claims.Producer == producers && claims.ClaimType.Equals(claim1.Type) 
                             && claims.ClaimIssuer == claim1.Issuer).FirstOrDefaultAsync();

        var res = 0;
        
        if (claim == null)
        {
            res = (await AddClaim(producers, claim1)).IsSuccess ? 1 : 0;
        }
        else
        {
            claim.ClaimValue = claim1.Value;
            res = await context.SaveChangesAsync();
        }
        
        
        return new ActionResult(res > 0);
    }
}