using DotNetEnv;
using Google.Apis.AnalyticsData.v1beta;
using Google.Apis.AnalyticsData.v1beta.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Microsoft.AspNetCore.Mvc;

Env.Load();

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Register Google Analytics Data Client
builder.Services.AddSingleton<AnalyticsDataService>(sp =>
{
    GoogleCredential credential;
    try 
    {
        // Tries to find credentials from GOOGLE_APPLICATION_CREDENTIALS environment variable
        // or default cloud environment credentials.
        credential = GoogleCredential.GetApplicationDefault();
    }
    catch (Exception)
    {
        // Fallback for local development if env var not set (User might need to run 'gcloud auth application-default login')
        // Or we warn them. For now, we assume it's set up or will fail at runtime.
         throw new InvalidOperationException("Could not load Google Credentials. Set GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'.");
    }

    if (credential.IsCreateScopedRequired)
    {
        credential = credential.CreateScoped(AnalyticsDataService.Scope.AnalyticsReadonly);
    }

    var service = new AnalyticsDataService(new BaseClientService.Initializer
    {
        HttpClientInitializer = credential,
        ApplicationName = "TravelMate Backend",
    });

    return service;
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

string? ga4PropertyId = Environment.GetEnvironmentVariable("GA4_PROPERTY_ID");
if (string.IsNullOrEmpty(ga4PropertyId))
{
    Console.WriteLine("Warning: GA4_PROPERTY_ID not set in .env");
    // Default or error? Let's just hold it and fail in the endpoint if needed, or fail startup.
    // For now, let's allow it to start but endpoint will likely fail.
} 

app.MapGet("/api/metrics/daily", async (
    [FromServices] AnalyticsDataService service,
    [FromQuery] string from, 
    [FromQuery] string to) =>
{
    // Basic validation
    // Basic validation: Check if it's a valid date OR a valid GA4 keyword
    bool IsValidDate(string date)
    {
        return DateTime.TryParse(date, out _) || 
               date == "today" || 
               date == "yesterday" || 
               date.EndsWith("daysAgo");
    }

    if (!IsValidDate(from) || !IsValidDate(to))
    {
        return Results.BadRequest(new { error = "Invalid date format. Use YYYY-MM-DD, 'today', 'yesterday', or 'NdaysAgo'." });
    }

    var request = new RunReportRequest
    {
        Property = $"properties/{ga4PropertyId}",
        DateRanges = new List<DateRange>
        {
            new DateRange { StartDate = from, EndDate = to }
        },
        Dimensions = new List<Dimension>
        {
            new Dimension { Name = "date" }
        },
        Metrics = new List<Metric>
        {
            new Metric { Name = "activeUsers" } // equivalent to Daily Active Users in this context often
            // Or strictly "activeUsers"
        }
    };

    try
    {
        var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();

        var result = response.Rows?.Select(row => new
        {
            date = FormatDate(row.DimensionValues[0].Value), // GA4 returns date as YYYYMMDD string usually
            dailyActiveUsers = int.Parse(row.MetricValues[0].Value)
        }) ?? Enumerable.Empty<object>();

        return Results.Ok(result);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex}");
        return Results.Problem($"Analytics API Error: {ex.Message}");
    }
})
.WithName("GetDailyMetrics")
.WithOpenApi();

app.MapGet("/api/metrics/general", async (
    [FromServices] AnalyticsDataService service) =>
{
    // "Global" means all time ideally, or a very long range.
    // GA4 retention might limit this for user-level data, but aggregated metrics usually go back further.
    var startDate = "2023-01-01"; // Arbitrary start date for the app
    var endDate = "today";

    var request = new RunReportRequest
    {
        Property = $"properties/{ga4PropertyId}",
        DateRanges = new List<DateRange>
        {
            new DateRange { StartDate = startDate, EndDate = endDate }
        },
        Metrics = new List<Metric>
        {
            new Metric { Name = "totalUsers" }, // Proxy for "nb de comptes"
            new Metric { Name = "eventCount" }  // Proxy for "nb de requètes"
        }
    };

    try
    {
        var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();

        var totalUsers = 0;
        var eventCount = 0;

        if (response.Rows != null && response.Rows.Count > 0)
        {
            var row = response.Rows[0];
            totalUsers = int.Parse(row.MetricValues[0].Value);
            eventCount = int.Parse(row.MetricValues[1].Value);
        }

        return Results.Ok(new
        {
            totalAccounts = totalUsers,
            totalRequests = eventCount
        });
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex}");
        return Results.Problem($"Analytics API Error: {ex.Message}");
    }

})
.WithName("GetGeneralMetrics")
.WithOpenApi();

    // 3. Tech Overview (OS & App Version)
    // GET /api/metrics/tech?from=x&to=y
    app.MapGet("/api/metrics/tech", async (
        [FromServices] AnalyticsDataService service,
        [FromQuery] string? from, 
        [FromQuery] string? to) =>
    {
        var startDate = from ?? "30daysAgo";
        var endDate = to ?? "today";

        // Request for OS
        var requestOS = new RunReportRequest
        {
            Property = $"properties/{ga4PropertyId}",
            DateRanges = new List<DateRange> { new DateRange { StartDate = startDate, EndDate = endDate } },
            Dimensions = new List<Dimension> { new Dimension { Name = "operatingSystem" } },
            Metrics = new List<Metric> { new Metric { Name = "activeUsers" } }
        };

        // Request for App Version
        var requestVersion = new RunReportRequest
        {
            Property = $"properties/{ga4PropertyId}",
            DateRanges = new List<DateRange> { new DateRange { StartDate = startDate, EndDate = endDate } },
            Dimensions = new List<Dimension> { new Dimension { Name = "appVersion" } },
            Metrics = new List<Metric> { new Metric { Name = "activeUsers" } } // use active users to see version adoption
        };

        try
        {
            var responseOS = await service.Properties.RunReport(requestOS, $"properties/{ga4PropertyId}").ExecuteAsync();
            var responseVersion = await service.Properties.RunReport(requestVersion, $"properties/{ga4PropertyId}").ExecuteAsync();

            var osData = responseOS.Rows?.Select(row => new { 
                os = row.DimensionValues[0].Value, 
                users = int.Parse(row.MetricValues[0].Value) 
            }) ?? Enumerable.Empty<object>();

            var versionData = responseVersion.Rows?.Select(row => new { 
                version = row.DimensionValues[0].Value, 
                users = int.Parse(row.MetricValues[0].Value) 
            }) ?? Enumerable.Empty<object>();

            return Results.Ok(new { operatingSystems = osData, appVersions = versionData });
        }
        catch (Exception ex)
        {
             return Results.Problem($"Analytics API Error: {ex.Message}");
        }
    })
    .WithName("GetTechOverview")
    .WithOpenApi();

    // 4. Top Events
    // GET /api/metrics/events?from=x&to=y
    app.MapGet("/api/metrics/events", async (
        [FromServices] AnalyticsDataService service,
        [FromQuery] string? from, 
        [FromQuery] string? to) =>
    {
        var startDate = from ?? "30daysAgo";
        var endDate = to ?? "today";

        var request = new RunReportRequest
        {
            Property = $"properties/{ga4PropertyId}",
            DateRanges = new List<DateRange> { new DateRange { StartDate = startDate, EndDate = endDate } },
            Dimensions = new List<Dimension> { new Dimension { Name = "eventName" } },
            Metrics = new List<Metric> { new Metric { Name = "eventCount" }, new Metric { Name = "activeUsers" } },
            OrderBys = new List<OrderBy> { new OrderBy { Desc = true, Metric = new MetricOrderBy { MetricName = "eventCount" } } },
            Limit = 20
        };

        try
        {
            var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();
            var result = response.Rows?.Select(row => new { 
                eventName = row.DimensionValues[0].Value, 
                count = int.Parse(row.MetricValues[0].Value),
                users = int.Parse(row.MetricValues[1].Value)
            }) ?? Enumerable.Empty<object>();

            return Results.Ok(result);
        }
         catch (Exception ex)
        {
             return Results.Problem($"Analytics API Error: {ex.Message}");
        }
    })
    .WithName("GetTopEvents")
    .WithOpenApi();

    // 5. Top Screens
    // GET /api/metrics/screens?from=x&to=y
    app.MapGet("/api/metrics/screens", async (
        [FromServices] AnalyticsDataService service,
        [FromQuery] string? from, 
        [FromQuery] string? to) =>
    {
        var startDate = from ?? "30daysAgo";
        var endDate = to ?? "today";

        var request = new RunReportRequest
        {
            Property = $"properties/{ga4PropertyId}",
            DateRanges = new List<DateRange> { new DateRange { StartDate = startDate, EndDate = endDate } },
            // GA4 uses 'unifiedScreenName' or 'pagePath' depending on setup, usually 'unifiedScreenName' for apps
            Dimensions = new List<Dimension> { new Dimension { Name = "unifiedScreenName" } }, 
            Metrics = new List<Metric> { new Metric { Name = "screenPageViews" }, new Metric { Name = "activeUsers" } },
            OrderBys = new List<OrderBy> { new OrderBy { Desc = true, Metric = new MetricOrderBy { MetricName = "screenPageViews" } } },
            Limit = 20
        };

        try
        {
            var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();
            var result = response.Rows?.Select(row => new { 
                screenName = row.DimensionValues[0].Value, 
                views = int.Parse(row.MetricValues[0].Value),
                users = int.Parse(row.MetricValues[1].Value)
            }) ?? Enumerable.Empty<object>();

            return Results.Ok(result);
        }
         catch (Exception ex)
        {
             return Results.Problem($"Analytics API Error: {ex.Message}");
        }
    })
    .WithName("GetTopScreens")
    .WithOpenApi();

    // 6. User Retention (New vs Returning)
    // GET /api/metrics/retention?from=x&to=y
    app.MapGet("/api/metrics/retention", async (
        [FromServices] AnalyticsDataService service,
        [FromQuery] string? from, 
        [FromQuery] string? to) =>
    {
        var startDate = from ?? "30daysAgo";
        var endDate = to ?? "today";

        var request = new RunReportRequest
        {
            Property = $"properties/{ga4PropertyId}",
            DateRanges = new List<DateRange> { new DateRange { StartDate = startDate, EndDate = endDate } },
            Dimensions = new List<Dimension> { new Dimension { Name = "newVsReturning" } }, 
            Metrics = new List<Metric> { new Metric { Name = "activeUsers" }, new Metric { Name = "sessions" } }
        };

        try
        {
            var response = await service.Properties.RunReport(request, $"properties/{ga4PropertyId}").ExecuteAsync();
            var result = response.Rows?.Select(row => new { 
                type = row.DimensionValues[0].Value, 
                users = int.Parse(row.MetricValues[0].Value),
                sessions = int.Parse(row.MetricValues[1].Value)
            }) ?? Enumerable.Empty<object>();

            return Results.Ok(result);
        }
        catch (Exception ex)
        {
             return Results.Problem($"Analytics API Error: {ex.Message}");
        }
    })
    .WithName("GetUserRetention")
    .WithOpenApi();

app.Run();

// Helper to format GA4 YYYYMMDD to YYYY-MM-DD
static string FormatDate(string gaDate)
{
    if (gaDate.Length == 8)
    {
        return $"{gaDate.Substring(0, 4)}-{gaDate.Substring(4, 2)}-{gaDate.Substring(6, 2)}";
    }
    return gaDate;
}
