using System.Text.Json.Serialization;
namespace PrismaticSync.Models;
///
/// On-disk scrape output. Shape matches the app's catalog import (a top-level "results" array of
/// snake_case product records), so the JSON drops straight into the import endpoint. "errors" tracks
/// failed URLs for resumable re-runs.
///
public class ScrapeOutput
{
[JsonPropertyName("results")] public List Results { get; set; } = new();
[JsonPropertyName("errors")] public List Errors { get; set; } = new();
}
/// One scraped product, in the import's expected field shape.
public class ProductRecord
{
[JsonPropertyName("sku")] public string Sku { get; set; } = "";
[JsonPropertyName("color_name")] public string ColorName { get; set; } = "";
[JsonPropertyName("description")] public string Description { get; set; } = "";
[JsonPropertyName("price_tiers")] public List PriceTiers { get; set; } = new();
[JsonPropertyName("safety_data_sheet_url")] public string SafetyDataSheetUrl { get; set; } = "";
[JsonPropertyName("technical_data_sheet_url")] public string TechnicalDataSheetUrl { get; set; } = "";
[JsonPropertyName("application_guide_url")] public string ApplicationGuideUrl { get; set; } = "";
[JsonPropertyName("sample_image_url")] public string SampleImageUrl { get; set; } = "";
[JsonPropertyName("product_url")] public string ProductUrl { get; set; } = "";
[JsonPropertyName("scraped_at")] public DateTime ScrapedAt { get; set; }
}
/// A quantity-break price tier — {min, max, price}. max is null for an open-ended top tier.
public class PriceTier
{
[JsonPropertyName("min")] public int? Min { get; set; }
[JsonPropertyName("max")] public int? Max { get; set; }
[JsonPropertyName("price")] public decimal Price { get; set; }
}
/// A URL that failed to scrape, kept so resumable runs can skip or retry it.
public class ScrapeError
{
[JsonPropertyName("product_url")] public string ProductUrl { get; set; } = "";
[JsonPropertyName("error")] public string Error { get; set; } = "";
[JsonPropertyName("scraped_at")] public DateTime ScrapedAt { get; set; }
}