using System.Globalization;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using NexusShell.Agent.Models;

namespace NexusShell.Agent;

public sealed class NexusAgentLocalClient
{
    private static readonly CultureInfo DaDk = CultureInfo.GetCultureInfo("da-DK");
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNameCaseInsensitive = true,
    };

    private readonly HttpClient _httpClient;
    private readonly string _baseUrl;
    private NexusAgentStatusResponse? _lastStatus;
    private NexusAgentDeviceResponse? _lastDevice;
    private bool _isConnected;

    public NexusAgentLocalClient(string localApiUrl)
    {
        _baseUrl = localApiUrl.TrimEnd('/');
        _httpClient = new HttpClient
        {
            BaseAddress = new Uri(_baseUrl),
            Timeout = TimeSpan.FromSeconds(2),
        };
    }

    public bool IsConnected => _isConnected;
    public NexusAgentStatusResponse? LastStatus => _lastStatus;
    public NexusAgentDeviceResponse? LastDevice => _lastDevice;

    public string AgentStatusLabel
    {
        get
        {
            if (!_isConnected || _lastStatus is null)
            {
                return "Offline";
            }

            var version = _lastStatus.AgentVersion;
            var heartbeat = _lastStatus.LastHeartbeatUtc;
            if (heartbeat is null)
            {
                return $"Tilsluttet · {version}";
            }

            var local = heartbeat.Value.ToLocalTime().ToString("HH:mm", DaDk);
            return $"Tilsluttet · {version} · {local}";
        }
    }

    public async Task<bool> RefreshStatusAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            var status = await _httpClient.GetFromJsonAsync<NexusAgentStatusResponse>(
                "/agent/status", JsonOptions, cancellationToken);
            var device = await _httpClient.GetFromJsonAsync<NexusAgentDeviceResponse>(
                "/agent/device", JsonOptions, cancellationToken);

            _lastStatus = status;
            _lastDevice = device;
            _isConnected = status is not null;
            return _isConnected;
        }
        catch
        {
            _isConnected = false;
            return false;
        }
    }

    public async Task<NexusAgentInventoryResponse?> GetInventoryAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<NexusAgentInventoryResponse>(
                "/agent/inventory", JsonOptions, cancellationToken);
        }
        catch
        {
            return null;
        }
    }

    public async Task<NexusAgentHealthResponse?> GetHealthAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<NexusAgentHealthResponse>(
                "/agent/health", JsonOptions, cancellationToken);
        }
        catch
        {
            return null;
        }
    }

    public async Task<NexusAgentIdentityResponse?> GetIdentityAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<NexusAgentIdentityResponse>(
                "/agent/identity", JsonOptions, cancellationToken);
        }
        catch
        {
            return null;
        }
    }

    public async Task<NexusAgentDeviceProfileResponse?> GetDeviceProfileAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<NexusAgentDeviceProfileResponse>(
                "/agent/device-profile", JsonOptions, cancellationToken);
        }
        catch
        {
            return null;
        }
    }

    public async Task<NexusAgentTrustResponse?> GetTrustAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<NexusAgentTrustResponse>(
                "/agent/trust", JsonOptions, cancellationToken);
        }
        catch
        {
            return null;
        }
    }
}
