namespace Extrudex.Domain.Interfaces;

/// <summary>
/// Service interface for calculating the cost of goods sold (COGS) per print job.
/// Uses the spool's purchase price and the print job's derived grams consumed
/// to produce a cost breakdown. Handles missing cost data gracefully by returning
/// warnings rather than throwing exceptions.
/// </summary>
public interface ICostPerPrintService
{
    /// <summary>
    /// Calculates the cost per print for a specific print job.
    /// </summary>
    /// <param name="printJobId">The unique identifier of the print job.</param>
    /// <param name="cancellationToken">Optional cancellation token.</param>
    /// <returns>
    /// A <see cref="CostPerPrintResult"/> containing the cost breakdown,
    /// or warnings if cost data is missing or incomplete.
    /// </returns>
    Task<CostPerPrintResult> CalculateAsync(Guid printJobId, CancellationToken cancellationToken = default);

    /// <summary>
    /// Calculates cost breakdowns for all print jobs associated with a specific spool.
    /// Useful for spool-level COGS reporting.
    /// </summary>
    /// <param name="spoolId">The unique identifier of the spool.</param>
    /// <param name="cancellationToken">Optional cancellation token.</param>
    /// <returns>
    /// A list of <see cref="CostPerPrintResult"/> for each print job on the spool.
    /// Jobs with missing cost data will include warnings.
    /// </returns>
    Task<IReadOnlyList<CostPerPrintResult>> CalculateBySpoolAsync(Guid spoolId, CancellationToken cancellationToken = default);
}

/// <summary>
/// Result of a cost-per-print calculation. Contains the cost breakdown
/// and any warnings about missing or incomplete cost data.
/// </summary>
public class CostPerPrintResult
{
    /// <summary>The print job identifier this result belongs to.</summary>
    public Guid PrintJobId { get; set; }

    /// <summary>Human-readable name of the print job.</summary>
    public string PrintName { get; set; } = string.Empty;

    /// <summary>The spool identifier that provided filament.</summary>
    public Guid SpoolId { get; set; }

    /// <summary>Serial number of the spool.</summary>
    public string SpoolSerial { get; set; } = string.Empty;

    /// <summary>Total millimeters of filament extruded.</summary>
    public decimal MmExtruded { get; set; }

    /// <summary>Derived grams consumed for this print.</summary>
    public decimal GramsDerived { get; set; }

    /// <summary>The spool's purchase price. Null if not recorded.</summary>
    public decimal? PurchasePrice { get; set; }

    /// <summary>The spool's total weight in grams when full.</summary>
    public decimal? WeightTotalGrams { get; set; }

    /// <summary>Cost per gram of filament. Null if purchase price or total weight is missing.</summary>
    public decimal? CostPerGram { get; set; }

    /// <summary>Calculated cost of this print job. Null if cost data is incomplete.</summary>
    public decimal? CostPerPrint { get; set; }

    /// <summary>
    /// Warnings about missing or incomplete data that prevented a full calculation.
    /// Empty when all data is available and the calculation succeeded.
    /// </summary>
    public List<string> Warnings { get; set; } = new();
}