namespace PowderCoating.Application.DTOs.AI; /// Request payload sent from JS wizard to the AiAnalyzeItem endpoint. public class AiAnalyzeItemRequest { /// TempIds of already-uploaded photos. public List PhotoTempIds { get; set; } = new(); // User-supplied context public string ReferenceDimension { get; set; } = string.Empty; // e.g. "longest edge is 18 inches" public int Quantity { get; set; } = 1; public string DesiredColor { get; set; } = string.Empty; public int CoatCount { get; set; } = 1; /// Material type — helps AI factor in prep, outgassing, cure time (e.g. "Cast Iron", "Aluminum"). public string? MaterialType { get; set; } /// Approximate weight in lbs per piece — used to factor heavy-handling surcharge into time estimate. public decimal? EstimatedWeightLbs { get; set; } // Follow-up support (null on first call) public List? ConversationHistory { get; set; } public string? FollowUpAnswer { get; set; } public int CompanyId { get; set; } /// /// Id of the the user selected before analyzing. /// When set, the controller loads that setup and passes it to the AI service so the /// correct blast rate is injected into the prompt. /// public int? BlastSetupId { get; set; } } public class AiConversationTurn { public string Role { get; set; } = string.Empty; // "user" | "assistant" public string Content { get; set; } = string.Empty; } /// Result returned to the JS wizard from AI analysis. public class AiAnalyzeItemResult { public bool Success { get; set; } public string? ErrorMessage { get; set; } // When NeedsFollowUp is true, the wizard shows FollowUpQuestion to the user public bool NeedsFollowUp { get; set; } public string? FollowUpQuestion { get; set; } public int FollowUpRound { get; set; } // 1 or 2 // Final item data (populated when NeedsFollowUp is false) public string? Description { get; set; } public decimal SurfaceAreaSqFt { get; set; } public string Complexity { get; set; } = "Moderate"; // Simple|Moderate|Complex|Extreme public int EstimatedMinutes { get; set; } public string? AiReasoning { get; set; } public string Confidence { get; set; } = "Medium"; // Low|Medium|High // Pricing preview (filled by server using company operating costs) public decimal EstimatedUnitPrice { get; set; } public decimal EstimatedTotal { get; set; } public decimal PowderCostPerLb { get; set; } public decimal CoverageSqFtPerLb { get; set; } = 30m; public decimal TransferEfficiency { get; set; } = 65m; // Raw conversation to pass back for follow-up round 2 public List ConversationHistory { get; set; } = new(); // AI-generated standardized tags from fixed taxonomy public List Tags { get; set; } = new(); // Historical price benchmark from completed jobs public AiBenchmarkResult? Benchmark { get; set; } // ID of the persisted AiItemPrediction record — returned on final result (not follow-up rounds). // The JS wizard stores this per-item so the controller can link prediction to QuoteItem/JobItem on save. public int? AiPredictionId { get; set; } // Pricing breakdown — helps users understand and sanity-check the estimate public AiPricingBreakdown? Breakdown { get; set; } } /// /// Display-only cost breakdown returned to the client. /// Contains computed dollar amounts only — rates, percentages, and coverage constants are intentionally excluded. /// public class AiPricingBreakdown { public decimal SurfaceAreaSqFt { get; set; } public decimal PowderLbsPerCoat { get; set; } public int CoatCount { get; set; } public decimal MaterialCost { get; set; } public decimal ConsumablesCost { get; set; } public int EstimatedMinutes { get; set; } /// Non-zero when a material-type minimum floor exists for this material. public int MaterialMinMinutes { get; set; } /// True when the floor was actually applied (AI returned less than the floor). public bool MinFloorApplied { get; set; } public decimal LaborCost { get; set; } public int OvenCycleMinutes { get; set; } public decimal OvenCost { get; set; } public bool RequiresPreheat { get; set; } public int PreheatMinutes { get; set; } public decimal PreheatCost { get; set; } public decimal SubtotalBeforeComplexity { get; set; } public string Complexity { get; set; } = string.Empty; public decimal ComplexityCharge { get; set; } public decimal SubtotalBeforeMarkup { get; set; } public decimal MarkupAmount { get; set; } public decimal UnitPrice { get; set; } } /// Request to recalculate AI item price when the user overrides sq ft, minutes, or complexity. public class AiRecalcPriceRequest { public decimal SurfaceAreaSqFt { get; set; } public int EstimatedMinutes { get; set; } public string Complexity { get; set; } = "Moderate"; public int CoatCount { get; set; } = 1; } /// Result of a price recalculation — returns the new unit price and a display-safe breakdown. public class AiRecalcPriceResult { public bool Success { get; set; } public decimal UnitPrice { get; set; } public AiPricingBreakdown? Breakdown { get; set; } } /// Historical price benchmark from completed jobs with similar complexity and size. public class AiBenchmarkResult { public int MatchCount { get; set; } public decimal MinPrice { get; set; } public decimal MaxPrice { get; set; } public decimal AvgPrice { get; set; } public string ComplexityLevel { get; set; } = string.Empty; public decimal SqFtRangeMin { get; set; } public decimal SqFtRangeMax { get; set; } } /// /// Company-specific AI context passed to the quote service on every analysis call. /// Contains optional free-text profile and recent accepted predictions as few-shot calibration examples. /// public class CompanyAiContext { /// Free-text description of the shop's specialties and pricing style (from Company Settings). public string? ProfileText { get; set; } /// Recent predictions the user accepted without override — used as few-shot calibration examples. public List AcceptedExamples { get; set; } = new(); } /// A single accepted-prediction record formatted for AI few-shot context. public class AiFewShotExample { public string Description { get; set; } = string.Empty; public decimal SurfaceAreaSqFt { get; set; } public string Complexity { get; set; } = string.Empty; public int EstimatedMinutes { get; set; } public decimal FinalUnitPrice { get; set; } public string? Tags { get; set; } } /// Internal structured response that Claude returns as JSON. public class ClaudeQuoteResponse { public string Description { get; set; } = string.Empty; public decimal SurfaceAreaSqFt { get; set; } public string Complexity { get; set; } = "Moderate"; public int EstimatedMinutes { get; set; } public bool RequiresPreheat { get; set; } public int PreheatMinutes { get; set; } public string Confidence { get; set; } = "Medium"; public bool NeedsFollowUp { get; set; } public string? FollowUpQuestion { get; set; } public string Reasoning { get; set; } = string.Empty; public List Tags { get; set; } = new(); }