84 lines
2.8 KiB
C#
84 lines
2.8 KiB
C#
using System.Text.RegularExpressions;
|
|
using EbayListingTool.Models;
|
|
|
|
namespace EbayListingTool.Services;
|
|
|
|
public record PriceSuggestion(decimal Price, string Source, string Label);
|
|
|
|
/// <summary>
|
|
/// Layered price suggestion: eBay live data → own listing history → AI estimate.
|
|
/// Returns the first source that produces a result, labelled so the UI can show
|
|
/// where the suggestion came from.
|
|
/// </summary>
|
|
public class PriceLookupService
|
|
{
|
|
private readonly EbayPriceResearchService _ebay;
|
|
private readonly SavedListingsService _history;
|
|
private readonly AiAssistantService _ai;
|
|
|
|
private static readonly Regex PriceRegex =
|
|
new(@"PRICE:\s*(\d+\.?\d*)", RegexOptions.IgnoreCase);
|
|
|
|
public PriceLookupService(
|
|
EbayPriceResearchService ebay,
|
|
SavedListingsService history,
|
|
AiAssistantService ai)
|
|
{
|
|
_ebay = ebay;
|
|
_history = history;
|
|
_ai = ai;
|
|
}
|
|
|
|
public async Task<PriceSuggestion?> GetSuggestionAsync(SavedListing listing)
|
|
{
|
|
// 1. eBay live listings
|
|
try
|
|
{
|
|
var result = await _ebay.GetLivePricesAsync(listing.Title);
|
|
if (result.HasSuggestion)
|
|
return new PriceSuggestion(
|
|
result.Suggested,
|
|
"ebay",
|
|
$"eBay suggests \u00A3{result.Suggested:F2} (from {result.Count} listings)");
|
|
}
|
|
catch { /* eBay unavailable — fall through */ }
|
|
|
|
// 2. Own saved listing history — same category, at least 2 data points
|
|
var sameCat = _history.Listings
|
|
.Where(l => l.Id != listing.Id
|
|
&& !string.IsNullOrWhiteSpace(l.Category)
|
|
&& l.Category.Equals(listing.Category, StringComparison.OrdinalIgnoreCase)
|
|
&& l.Price > 0)
|
|
.Select(l => l.Price)
|
|
.ToList();
|
|
|
|
if (sameCat.Count >= 2)
|
|
{
|
|
var avg = Math.Round(sameCat.Average(), 2);
|
|
return new PriceSuggestion(
|
|
avg,
|
|
"history",
|
|
$"Your avg for {listing.Category}: \u00A3{avg:F2} ({sameCat.Count} listings)");
|
|
}
|
|
|
|
// 3. AI estimate
|
|
try
|
|
{
|
|
var response = await _ai.SuggestPriceAsync(listing.Title, listing.ConditionNotes);
|
|
var match = PriceRegex.Match(response);
|
|
if (match.Success
|
|
&& decimal.TryParse(match.Groups[1].Value,
|
|
System.Globalization.NumberStyles.Any,
|
|
System.Globalization.CultureInfo.InvariantCulture,
|
|
out var price)
|
|
&& price > 0)
|
|
{
|
|
return new PriceSuggestion(price, "ai", $"AI estimate: \u00A3{price:F2}");
|
|
}
|
|
}
|
|
catch { /* AI unavailable */ }
|
|
|
|
return null;
|
|
}
|
|
}
|