namespace PrismaticSync.Infrastructure;
/// Strongly-typed config bound from the "Sync" section of appsettings.json.
public class SyncConfig
{
public string BaseUrl { get; set; } = "https://www.prismaticpowders.com";
public string ColorsPath { get; set; } = "/shop/powder-coating-colors";
public string ProductUrlsFile { get; set; } = "product-urls.txt";
public string OutputJsonFile { get; set; } = "prismatic_powders.json";
public string LogFile { get; set; } = "prismatic-sync.log";
/// Politeness delay between product scrapes (randomized within the range).
public int MinDelaySeconds { get; set; } = 6;
public int MaxDelaySeconds { get; set; } = 14;
/// On a 403/block, cool down this many seconds × the consecutive-block count, then retry.
public int BlockedCooldownSeconds { get; set; } = 120;
/// Upper bound on a single cooldown so escalation can't run away.
public int BlockedCooldownMaxSeconds { get; set; } = 600;
/// How many times to cool-down-and-retry a blocked product before recording it as an error.
public int BlockedMaxRetries { get; set; } = 3;
/// Take a longer rest after this many products (0 disables). Eases load and looks less robotic.
public int LongRestEveryProducts { get; set; } = 150;
/// Length of the periodic long rest, in seconds.
public int LongRestSeconds { get; set; } = 45;
/// Extra settle time after a product page loads before reading it.
public int PageSettleSeconds { get; set; } = 4;
/// Pause after each scroll while a listing lazy-loads more items.
public int ScrollWaitMs { get; set; } = 1500;
/// Hard cap on scrolls per listing, as a safety stop.
public int MaxScrolls { get; set; } = 400;
/// Full discovery: stop a listing after this many scrolls add no new links.
public int StopAfterNoNewScrolls { get; set; } = 10;
///
/// Incremental discovery: stop the newest-first listing after this many consecutive scrolls
/// that surfaced only already-known URLs — i.e. we've scrolled past the new products.
///
public int StopAfterKnownScrolls { get; set; } = 8;
/// Color filter params used by full discovery.
public string[] ColorParams { get; set; } = Array.Empty();
public ImportConfig Import { get; set; } = new();
public string ColorsUrl => $"{BaseUrl.TrimEnd('/')}{ColorsPath}";
}
/// Where and how to push the scraped catalog into the app.
public class ImportConfig
{
/// Full URL of the app's token-authenticated catalog import endpoint.
public string EndpointUrl { get; set; } = "";
/// Shared secret sent in the X-Import-Token header. Must match the app's config.
public string Token { get; set; } = "";
/// Vendor name applied to every record on import.
public string VendorName { get; set; } = "Prismatic Powders";
}