namespace Gateway.Models;
// ════════════════════════════════════════════════
// Request: Client → Gateway
// ════════════════════════════════════════════════
public sealed class ChannelForecastRequest
{
/// Advertising objective: awareness, traffic, leads, sales
public string Objective { get; set; } = "traffic";
/// Business category from wizard Step 1
public string? BusinessCategory { get; set; }
/// Keywords from URL analysis (Step 1)
public List Keywords { get; set; } = new();
/// Geo targeting from audience step
public ForecastGeoTargeting? GeoTargeting { get; set; }
/// Audience parameters from Step 2
public ForecastAudience? Audience { get; set; }
/// Monthly budget in whole dollars
public decimal MonthlyBudget { get; set; }
/// Channels to estimate (defaults to all selected)
public List? Channels { get; set; }
}
public sealed class ForecastGeoTargeting
{
public List? ZipCodes { get; set; }
public double? RadiusMiles { get; set; }
public List? GeoTargetIds { get; set; }
}
public sealed class ForecastAudience
{
public int? AgeMin { get; set; }
public int? AgeMax { get; set; }
public List? Genders { get; set; }
public List? Interests { get; set; }
}
// ════════════════════════════════════════════════
// Response: Gateway → Client (normalized)
// ════════════════════════════════════════════════
public sealed class ChannelForecastResponse
{
public bool Ok { get; set; } = true;
public string Objective { get; set; } = string.Empty;
public decimal TotalBudget { get; set; }
public List Channels { get; set; } = new();
public ForecastRecommendation? Recommendation { get; set; }
public ForecastMeta Metadata { get; set; } = new();
}
public sealed class ChannelEstimate
{
public string Provider { get; set; } = string.Empty;
public int AllocationPercent { get; set; }
public decimal AllocatedBudget { get; set; }
public ChannelEstimateMetrics Estimates { get; set; } = new();
public double EfficiencyScore { get; set; }
public string StrengthLabel { get; set; } = string.Empty;
public string Confidence { get; set; } = "none";
public string DataSource { get; set; } = "none";
}
public sealed class ChannelEstimateMetrics
{
public double Impressions { get; set; }
public double? Reach { get; set; }
public double Clicks { get; set; }
public double Conversions { get; set; }
public decimal AvgCpc { get; set; }
public decimal AvgCpm { get; set; }
public decimal? EstimatedCpa { get; set; }
public double Ctr { get; set; }
}
public sealed class ForecastRecommendation
{
public string Summary { get; set; } = string.Empty;
public List Highlights { get; set; } = new();
}
public sealed class ForecastMeta
{
public DateTimeOffset GeneratedAt { get; set; } = DateTimeOffset.UtcNow;
public string ForecastPeriod { get; set; } = "30 days";
}
// ════════════════════════════════════════════════
// Objective-weighted scoring
// ════════════════════════════════════════════════
public sealed class MetricWeights
{
public double Reach { get; }
public double Impressions { get; }
public double Cpm { get; }
public double Clicks { get; }
public double Cpc { get; }
public double Ctr { get; }
public double Conversions { get; }
public double Cpa { get; }
public MetricWeights(double reach, double impressions, double cpm,
double clicks, double cpc, double ctr, double conversions, double cpa)
{
Reach = reach; Impressions = impressions; Cpm = cpm;
Clicks = clicks; Cpc = cpc; Ctr = ctr;
Conversions = conversions; Cpa = cpa;
}
}
public static class ObjectiveWeights
{
public static readonly Dictionary Weights = new(StringComparer.OrdinalIgnoreCase)
{
// reach imp cpm clicks cpc ctr conv cpa
["awareness"] = new MetricWeights(0.35, 0.25, 0.20, 0.05, 0.05, 0.05, 0.00, 0.00),
["traffic"] = new MetricWeights(0.05, 0.10, 0.10, 0.30, 0.30, 0.15, 0.00, 0.00),
["leads"] = new MetricWeights(0.05, 0.05, 0.05, 0.15, 0.15, 0.10, 0.25, 0.20),
["sales"] = new MetricWeights(0.05, 0.05, 0.05, 0.10, 0.10, 0.10, 0.30, 0.25),
};
/// Fallback: balanced weights if objective not recognized
public static readonly MetricWeights Default =
new(0.10, 0.10, 0.10, 0.20, 0.20, 0.10, 0.10, 0.10);
public static MetricWeights For(string objective)
=> Weights.TryGetValue(objective, out var w) ? w : Default;
}