using GoogleApi.Configuration;
using GoogleApi.Models;
using Microsoft.Extensions.Options;
using Google.Ads.GoogleAds;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V22.Errors;
using Google.Ads.GoogleAds.V22.Services;
namespace GoogleApi.Services;
using GAdsServices = global::Google.Ads.GoogleAds.Services;
///
/// Reporting service for pulling campaign performance metrics from Google Ads.
/// Supports both real API calls and emulated responses for development.
///
/// Operations:
/// - GetCampaignReport: Daily metrics for a specific campaign
/// - GetAccountReport: Daily metrics across all campaigns in an account
/// - GetCampaignList: Campaign status/budget summary (lightweight)
///
public sealed class ReportingService
{
private readonly GoogleAdsConfig _config;
private readonly GoogleAdsClientFactory _clientFactory;
private readonly ILogger _logger;
public ReportingService(
IOptions config,
GoogleAdsClientFactory clientFactory,
ILogger logger)
{
_config = config.Value;
_clientFactory = clientFactory;
_logger = logger;
}
///
/// Get daily campaign performance report.
/// Returns impressions, clicks, spend, conversions, conversion value per day.
///
public async Task GetCampaignReportAsync(
ProviderRequest request, GoogleAdsContext context, string requestId, CancellationToken ct)
{
var payload = request.GetPayload();
if (string.IsNullOrWhiteSpace(payload.CampaignId))
return ProviderResponse.Fail(requestId, "VALIDATION", "CampaignId is required");
var startDate = payload.StartDate ?? DateTime.UtcNow.AddDays(-30).ToString("yyyy-MM-dd");
var endDate = payload.EndDate ?? DateTime.UtcNow.AddDays(-1).ToString("yyyy-MM-dd");
if (_clientFactory.IsRealApiEnabled && !string.IsNullOrWhiteSpace(context.CustomerId))
return await GetCampaignReportRealAsync(payload.CampaignId, startDate, endDate, context, requestId, ct);
return GetCampaignReportEmulated(payload.CampaignId, startDate, endDate, requestId);
}
///
/// Get daily account-level performance report across all campaigns.
/// Used for syncing metrics into tbPerformanceMetric.
///
public async Task GetAccountReportAsync(
ProviderRequest request, GoogleAdsContext context, string requestId, CancellationToken ct)
{
var payload = request.GetPayload();
var startDate = payload.StartDate ?? DateTime.UtcNow.AddDays(-7).ToString("yyyy-MM-dd");
var endDate = payload.EndDate ?? DateTime.UtcNow.AddDays(-1).ToString("yyyy-MM-dd");
if (_clientFactory.IsRealApiEnabled && !string.IsNullOrWhiteSpace(context.CustomerId))
return await GetAccountReportRealAsync(startDate, endDate, context, requestId, ct);
return GetAccountReportEmulated(startDate, endDate, requestId);
}
// ════════════════════════════════════════════════
// Real API Implementation
// ════════════════════════════════════════════════
private async Task GetCampaignReportRealAsync(
string campaignId, string startDate, string endDate,
GoogleAdsContext context, string requestId, CancellationToken ct)
{
try
{
var client = _clientFactory.CreateClient(context);
var gaService = client.GetService(GAdsServices.V22.GoogleAdsService);
// Extract numeric campaign ID from resource name if needed
var numericId = campaignId.Contains('/') ? campaignId.Split('/').Last() : campaignId;
var query = $@"
SELECT
campaign.id,
campaign.name,
campaign.status,
segments.date,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.all_conversions,
metrics.ctr,
metrics.average_cpc
FROM campaign
WHERE campaign.id = {numericId}
AND segments.date BETWEEN '{startDate}' AND '{endDate}'
ORDER BY segments.date";
var rows = new List