using Extrudex.Domain.Entities;
using Extrudex.Domain.Interfaces;
using Extrudex.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Extrudex.Infrastructure.Services;

/// <summary>
/// EF Core–backed implementation of the filament usage service.
/// Persists usage records to the database and provides query methods
/// for retrieving usage by print job or spool.
/// </summary>
public class FilamentUsageService : IFilamentUsageService
{
    private readonly ExtrudexDbContext _dbContext;
    private readonly ILogger<FilamentUsageService> _logger;

    public FilamentUsageService(
        ExtrudexDbContext dbContext,
        ILogger<FilamentUsageService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<FilamentUsage> RecordUsageAsync(
        Guid printJobId,
        Guid spoolId,
        Guid printerId,
        decimal gramsUsed,
        decimal mmExtruded,
        string? notes = null,
        CancellationToken cancellationToken = default)
    {
        var usage = new FilamentUsage
        {
            PrintJobId = printJobId,
            SpoolId = spoolId,
            PrinterId = printerId,
            GramsUsed = gramsUsed,
            MmExtruded = mmExtruded,
            RecordedAt = DateTime.UtcNow,
            Notes = notes
        };

        _dbContext.FilamentUsages.Add(usage);
        await _dbContext.SaveChangesAsync(cancellationToken);

        _logger.LogInformation(
            "Recorded filament usage: {Grams}g / {Mm}mm for print job {JobId} on spool {SpoolId}",
            gramsUsed, mmExtruded, printJobId, spoolId);

        return usage;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<FilamentUsage>> GetByPrintJobAsync(
        Guid printJobId,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext.FilamentUsages
            .Where(u => u.PrintJobId == printJobId)
            .OrderByDescending(u => u.RecordedAt)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<FilamentUsage>> GetBySpoolAsync(
        Guid spoolId,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext.FilamentUsages
            .Where(u => u.SpoolId == spoolId)
            .OrderByDescending(u => u.RecordedAt)
            .ToListAsync(cancellationToken);
    }
}