namespace IntelligenceApi.Models; // ════════════════════════════════════════════════ // Request: Gateway → IntelligenceApi // Gateway injects clientCategory from ClientContext // before forwarding the wizard's forecast request. // ════════════════════════════════════════════════ public sealed class SpendDistributionRequest { /// /// Client category — the primary engine selector. /// Values: General | Franchisee | Franchisor | FoodFranchisee | etc. /// Injected by the Gateway from ClientContext.ClientCategory. /// public string ClientCategory { get; set; } = "General"; /// Advertising objective: awareness, traffic, leads, sales public string Objective { get; set; } = "traffic"; /// Business category from wizard Step 1 (industry) public string? BusinessCategory { get; set; } /// Keywords from URL analysis public List Keywords { get; set; } = new(); /// Geo targeting from audience step public GeoTargeting? GeoTargeting { get; set; } /// Audience parameters public AudienceParams? Audience { get; set; } /// Monthly budget in whole dollars public decimal MonthlyBudget { get; set; } /// Channels to estimate public List? Channels { get; set; } /// /// Provider base URLs forwarded from Gateway config. /// Allows engines to call providers without needing their own config. /// public Dictionary? ProviderUrls { get; set; } /// Internal API keys forwarded from Gateway config. public Dictionary? InternalKeys { get; set; } } public sealed class GeoTargeting { public List? ZipCodes { get; set; } public double? RadiusMiles { get; set; } public List? GeoTargetIds { get; set; } } public sealed class AudienceParams { public int? AgeMin { get; set; } public int? AgeMax { get; set; } public List? Genders { get; set; } public List? Interests { get; set; } } // ════════════════════════════════════════════════ // Response: IntelligenceApi → Gateway → Client // Identical shape to ChannelForecastResponse in // the Gateway so no client changes are needed. // ════════════════════════════════════════════════ public sealed class SpendDistributionResponse { 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 DistributionRecommendation? Recommendation { get; set; } public DistributionMeta Metadata { get; set; } = new(); } public sealed class ChannelAllocation { public string Provider { get; set; } = string.Empty; public int AllocationPercent { get; set; } public decimal AllocatedBudget { get; set; } public AllocationMetrics 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 AllocationMetrics { 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 DistributionRecommendation { public string Summary { get; set; } = string.Empty; public List Highlights { get; set; } = new(); } public sealed class DistributionMeta { public DateTimeOffset GeneratedAt { get; set; } = DateTimeOffset.UtcNow; public string ForecastPeriod { get; set; } = "30 days"; /// Which engine handled this request — useful for debugging and billing. public string Engine { get; set; } = "General"; }