using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualBasic.Devices;

namespace HeartbeatSender;

public class heartbeatSender
{
    private readonly HttpClient httpClient = new();
    private string token = "";
    private string branchName = "";
    private string heartbeatDomain = "";
    private CancellationTokenSource? cancellationTokenSource;

    public heartbeatSender()
    {
        this.heartbeatDomain = Utils.Env.Get("HeartBeatUrl", ""); 

        // 在建構子中啟動背景心跳任務
        _ = Task.Run(() => StartAsync());
    }
    public async Task StartAsync()
    {
        cancellationTokenSource = new CancellationTokenSource();

        while (!cancellationTokenSource.IsCancellationRequested)
        {
            try
            {
                if (string.IsNullOrEmpty(token))
                {
                    bool loginSuccess = await LoginAndGetTokenAsync();
                    Console.WriteLine(loginSuccess ? "心跳登入成功" : "心跳登入失敗");
                }

                if (!string.IsNullOrEmpty(token))
                {
                    await SendHeartbeatAsync();
                }

                await Task.Delay(TimeSpan.FromMinutes(1), cancellationTokenSource.Token);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"心跳任務錯誤：{ex.Message}");
                await Task.Delay(5000); // 錯誤後延遲再跑
            }
        }
    }

    public void Stop()
    {
        cancellationTokenSource?.Cancel();
        Console.WriteLine("心跳任務已停止");
    }

    public async Task<bool> LoginAndGetTokenAsync()
    {
        var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/receiveRegister";
        var loginPayload = new
        {
            email = "MachineKTV@gmail.com",
            password = "aa147258-"
        };

        var result = await SendPostAsync<JsonElement>(url, loginPayload);

        if (result.ValueKind == JsonValueKind.Object &&
            result.TryGetProperty("data", out JsonElement data))
        {
            token = data.GetProperty("token").GetString()!;
            branchName = data.GetProperty("branch_name").GetString()!;
            return true;
        }

        return false;
    }

    public async Task SendHeartbeatAsync()
    {
        var url = $"{heartbeatDomain.TrimEnd('/')}/api/room/heartbeat";
        string hostName = Dns.GetHostName();

        var heartbeatPayload = new
        {
            branch_name = branchName,
            hostname = "PC" + hostName[^3..],
            ip = GetLocalIPv4(),
            cpu = GetCpuUsage(),
            memory = GetTotalMemoryInMB(),
            disk = GetDiskTotalSizeInGB()
        };

        await SendPostAsync<JsonElement>(url, heartbeatPayload, token);
        Console.WriteLine($"心跳送出成功: {DateTime.Now:HH:mm:ss}");
    }

    private async Task<T?> SendPostAsync<T>(string url, object payload, string? bearerToken = null)
    {
        var json = JsonSerializer.Serialize(payload);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var request = new HttpRequestMessage(HttpMethod.Post, url)
        {
            Content = content
        };

        if (!string.IsNullOrWhiteSpace(bearerToken))
        {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
        }

        var response = await httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        string responseJson = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<T>(responseJson);
    }

    private static string GetLocalIPv4()
    {
        foreach (var ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
                return ip.ToString();
        }
        return "127.0.0.1";
    }

    private float GetCpuUsage()
    {
        using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        cpuCounter.NextValue();
        Thread.Sleep(100);
        return cpuCounter.NextValue();
    }

    private float GetTotalMemoryInMB()
    {
        var ci = new ComputerInfo();
        return (ci.TotalPhysicalMemory - ci.AvailablePhysicalMemory) / 1024f;
    }

    private float GetDiskTotalSizeInGB(string driveLetter = "C")
    {
        var drive = new DriveInfo(driveLetter);
        return drive.TotalSize / (1024f * 1024f * 1024f);
    }
}
