using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

var builder = DistributedApplication.CreateBuilder(args);

var postgres = builder.AddPostgres("postgres")
    .WithDataVolume();

var gerbilDb = postgres.AddDatabase("gerbilmanager");

// Stable, LAN-facing HTTP port for the API (matches the SPA's default base URL).
const int ApiHttpPort = 5179;

var webapi = builder.AddProject<Projects.GerbilManagerWebAPI>("webapi")
    .WithReference(gerbilDb)
    .WaitFor(gerbilDb)
    // Pin the port so the phone-facing URL doesn't change between launches.
    // Proxyless so the app binds the port directly — Program.cs then widens the
    // host to 0.0.0.0 for LAN access (the DCP proxy binds localhost only).
    .WithEndpoint("http", e => { e.Port = ApiHttpPort; e.IsProxied = false; }, createIfNotExists: false)
    .WithExternalHttpEndpoints();

// The machine's LAN IP — the SPA runs in the phone's browser, so it must reach
// the API at this address, not "localhost" (which would be the phone itself).
var lanIp = GetLanIpAddress();

builder.AddViteApp("frontend", "../gerbil-manager-web")
    .WithReference(webapi)
    .WaitFor(webapi)
    // Pin a stable port for the phone bookmark (Vite default 5173). Proxyless so
    // the Vite dev server binds the port directly; vite.config host:true makes it
    // bind 0.0.0.0 for LAN access.
    .WithEndpoint("http", e => { e.Port = 5173; e.IsProxied = false; }, createIfNotExists: false)
    .WithExternalHttpEndpoints()
    .WithEnvironment(context =>
    {
        // VITE_API_BASE_URL is read by the Vite dev server at launch (see
        // src/api/client.ts). Point it at the API's LAN-reachable URL.
        context.EnvironmentVariables["VITE_API_BASE_URL"] = $"http://{lanIp}:{ApiHttpPort}";
    });

builder.Build().Run();

// Picks the IPv4 address of the active physical LAN adapter (Wi-Fi/Ethernet),
// skipping loopback and virtual adapters (WSL/Hyper-V). Recomputed each launch
// so it follows DHCP changes.
static string GetLanIpAddress()
{
    var candidates = NetworkInterface.GetAllNetworkInterfaces()
        .Where(ni => ni.OperationalStatus == OperationalStatus.Up)
        .Where(ni => ni.NetworkInterfaceType is NetworkInterfaceType.Wireless80211
                                              or NetworkInterfaceType.Ethernet)
        .Where(ni => !ni.Description.Contains("Hyper-V", StringComparison.OrdinalIgnoreCase)
                  && !ni.Description.Contains("Virtual", StringComparison.OrdinalIgnoreCase)
                  && !ni.Name.Contains("WSL", StringComparison.OrdinalIgnoreCase)
                  && !ni.Name.Contains("vEthernet", StringComparison.OrdinalIgnoreCase))
        // Prefer adapters that have a default gateway (i.e. a real network path).
        .OrderByDescending(ni => ni.GetIPProperties().GatewayAddresses.Count > 0);

    foreach (var ni in candidates)
    {
        var ip = ni.GetIPProperties().UnicastAddresses
            .FirstOrDefault(a => a.Address.AddressFamily == AddressFamily.InterNetwork
                              && !IPAddress.IsLoopback(a.Address));
        if (ip is not null)
        {
            return ip.Address.ToString();
        }
    }

    return "localhost";
}
