using Extrudex.Domain.Entities;
using Extrudex.Domain.Enums;
using Extrudex.Domain.Interfaces;
using Extrudex.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace Extrudex.Infrastructure.Services;

/// <summary>
/// Implementation of <see cref="IUsageLogService"/> that persists usage entries
/// to the usage_logs table via EF Core.
/// </summary>
public class UsageLogService : IUsageLogService
{
    private readonly ExtrudexDbContext _dbContext;

    /// <summary>
    /// Initializes a new instance of the <see cref="UsageLogService"/> class.
    /// </summary>
    /// <param name="dbContext">The EF Core database context for data persistence.</param>
    public UsageLogService(ExtrudexDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    /// <inheritdoc/>
    public async Task<UsageLog> RecordUsageAsync(
        Guid spoolId,
        decimal gramsUsed,
        DataSource dataSource,
        Guid? printerId = null,
        Guid? printJobId = null,
        decimal? mmExtruded = null,
        DateTime? usageTimestamp = null,
        string? notes = null)
    {
        var entry = new UsageLog
        {
            SpoolId = spoolId,
            GramsUsed = gramsUsed,
            DataSource = dataSource,
            PrinterId = printerId,
            PrintJobId = printJobId,
            MmExtruded = mmExtruded,
            UsageTimestamp = usageTimestamp ?? DateTime.UtcNow,
            Notes = notes
        };

        _dbContext.UsageLogs.Add(entry);
        await _dbContext.SaveChangesAsync();

        return entry;
    }

    /// <inheritdoc/>
    public async Task<IEnumerable<UsageLog>> GetBySpoolAsync(Guid spoolId, CancellationToken cancellationToken = default)
    {
        return await _dbContext.UsageLogs
            .Where(u => u.SpoolId == spoolId)
            .OrderByDescending(u => u.UsageTimestamp)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<IEnumerable<UsageLog>> GetByPrinterAsync(Guid printerId, CancellationToken cancellationToken = default)
    {
        return await _dbContext.UsageLogs
            .Where(u => u.PrinterId == printerId)
            .OrderByDescending(u => u.UsageTimestamp)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<IEnumerable<UsageLog>> GetByPrintJobAsync(Guid printJobId, CancellationToken cancellationToken = default)
    {
        return await _dbContext.UsageLogs
            .Where(u => u.PrintJobId == printJobId)
            .OrderByDescending(u => u.UsageTimestamp)
            .ToListAsync(cancellationToken);
    }
}