using System.Net.Http.Json;
using System.Text.Json;
using Lumi.Companion.Protocol;

namespace Lumi.Companion.Core;

public sealed class PairingClient(HttpClient http)
{
    public async Task<DeviceCredential> PairAsync(string packagePath, object device, CancellationToken cancellationToken)
    {
        var bootstrap = JsonSerializer.Deserialize<PairingBootstrap>(await File.ReadAllBytesAsync(packagePath, cancellationToken), ProtocolV1.JsonOptions)
            ?? throw new InvalidDataException("Pairing package is invalid.");
        if (bootstrap.Format != "lumi-companion-bootstrap-v1" || bootstrap.ProtocolVersion != 1)
            throw new InvalidDataException("Pairing package is incompatible with this companion.");
        if (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() >= bootstrap.ExpiresAt)
            throw new InvalidDataException("Pairing package has expired. Download a new package from Lumi.");
        var exchangeUri = new Uri(bootstrap.ExchangeUrl);
        var hostUri = new Uri(bootstrap.Host);
        var secure = exchangeUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) && hostUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase);
        var localHttp = exchangeUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) && hostUri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) && exchangeUri.IsLoopback && hostUri.IsLoopback;
        if ((!secure && !localHttp) || exchangeUri.GetLeftPart(UriPartial.Authority) != hostUri.GetLeftPart(UriPartial.Authority))
            throw new InvalidDataException("Pairing requires HTTPS unless the package explicitly uses one matching localhost origin.");
        using var response = await http.PostAsJsonAsync(bootstrap.ExchangeUrl, new { token = bootstrap.Token, device }, ProtocolV1.JsonOptions, cancellationToken);
        var body = await response.Content.ReadAsStringAsync(cancellationToken);
        if (!response.IsSuccessStatusCode) throw new InvalidOperationException($"Pairing failed: {body}");
        using var json = JsonDocument.Parse(body);
        return new DeviceCredential(
            json.RootElement.GetProperty("device_id").GetString()!, json.RootElement.GetProperty("device_secret").GetString()!,
            json.RootElement.GetProperty("host").GetString()!, json.RootElement.GetProperty("capabilities").EnumerateArray().Select(item => item.GetString()!).ToArray(),
            json.RootElement.GetProperty("protocol_version").GetInt32());
    }
}
