using Predictalytics.Api.Endpoints;
using Predictalytics.Api.Security;
using Predictalytics.Infrastructure;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using System;

namespace Predictalytics.Api;

/// <summary>
/// Configures the API WebApplication. Used by the embedded Kestrel server.
/// </summary>
public static class ApiConfiguration
{
    public static WebApplication ConfigureApi(WebApplicationBuilder builder, string? connectionStringOverride = null)
    {
        builder.Services.AddPredictalytics(builder.Configuration, connectionStringOverride);
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen(c => c.SwaggerDoc("v1",
            new() { Title = "Predictalytics Analytics API", Version = "v1" }));
        var allowedOrigins = builder.Configuration.GetSection("ApiSettings:AllowedOrigins").Get<string[]>() 
            ?? new[] { "http://localhost:5000" };
        builder.Services.AddCors(o => o.AddDefaultPolicy(p =>
            p.WithOrigins(allowedOrigins).AllowAnyMethod().AllowAnyHeader()));

        var app = builder.Build();

        app.UseCors();
        app.UseSwagger();
        app.UseSwaggerUI();
        app.UseDefaultFiles();
        app.UseStaticFiles(new StaticFileOptions
        {
            // Internal dashboard: always revalidate so UI fixes reach the browser immediately.
            OnPrepareResponse = ctx => ctx.Context.Response.Headers.CacheControl = "no-cache"
        });

        // Register both Read and Control endpoints for the local host
        app.MapPredictalyticsReadEndpoints();
        app.MapPredictalyticsControlEndpoints();

        return app;
    }

    /// <summary>
    /// Registers all Read-only endpoints designed for viewing and analysis.
    /// Safely exposed publicly since these endpoints perform no DB writes.
    /// </summary>
    public static void MapPredictalyticsReadEndpoints(this IEndpointRouteBuilder routes)
    {
        routes.MapDashboardEndpoints();
        routes.MapTraderReadEndpoints();
        routes.MapAlertReadEndpoints();
        routes.MapMarketEndpoints();
        routes.MapSearchEndpoints();
        routes.MapWatchlistEndpoints();
        routes.MapPortfolioEndpoints();
        routes.MapCoMovementEndpoints();
        routes.MapGet("/api/health", () => Results.Ok(new { Status = "OK", Timestamp = DateTime.UtcNow }));

        // Meldet der WebUI den tatsaechlichen Zustand, nicht eine Konfigurationsabsicht:
        // ControlState wird beim Mappen der Steuerendpunkte gesetzt.
        routes.MapGet("/api/capabilities", () => Results.Ok(new
        {
            CanControl = ControlEndpointsMapped,
            AuthRequired = ControlEndpointsRequireToken,
            TokenHeader = ControlEndpointsRequireToken ? ApiTokenFilter.HeaderName : null
        }));
    }

    /// <summary>Ob die Steuerendpunkte ueberhaupt erreichbar sind.</summary>
    public static bool ControlEndpointsMapped { get; private set; }

    /// <summary>Ob sie einen Token verlangen.</summary>
    public static bool ControlEndpointsRequireToken { get; private set; }

    /// <summary>
    /// Registers all Control endpoints that trigger crawls, modifications, or database updates.
    /// </summary>
    /// <param name="requiredToken">
    /// Wenn gesetzt, verlangt jeder Aufruf den Header
    /// <see cref="ApiTokenFilter.HeaderName"/> mit diesem Wert. Null oder leer bedeutet
    /// ungeschuetzt — das ist nur vertretbar, solange Kestrel an localhost gebunden ist.
    /// </param>
    public static void MapPredictalyticsControlEndpoints(this IEndpointRouteBuilder routes, string? requiredToken = null)
    {
        IEndpointRouteBuilder target = routes;

        if (!string.IsNullOrWhiteSpace(requiredToken))
        {
            // Leere Gruppe ohne Praefix: sie dient nur dazu, den Filter an alle
            // darin gemappten Endpunkte zu haengen.
            target = routes.MapGroup("").AddEndpointFilter(new ApiTokenFilter(requiredToken!));
            ControlEndpointsRequireToken = true;
        }

        target.MapTraderControlEndpoints();
        target.MapAlertControlEndpoints();
        target.MapJobEndpoints();
        target.MapDevEndpoints();

        ControlEndpointsMapped = true;
    }
}
