using System.Text.Json.Nodes;
using CliWrap;
using CliWrap.Buffered;

namespace InnovEnergy.App.EmuMeterDriver;

public readonly struct Nic
{
    private static Command IpCommand { get; } = Cli
                                               .Wrap("/sbin/ip")
                                               .WithValidation(CommandResultValidation.None);
    
    private readonly JsonNode _Node;

    private Nic(JsonNode node)
    {
        _Node = node;
    }

    public Boolean IsEthernet
    {
        get
        {
            try
            {
                return _Node["link_type"]!.GetValue<String>() == "ether";
            }
            catch
            {
                return false;
            }
        }
    }

    public Boolean IsUp
    {
        get
        {
            // ReSharper disable once StringLiteralTypo
            try
            {
                return _Node["operstate"]!.GetValue<String>() == "UP";
            }
            catch
            {
                return false;
            }
        }
    }

    public IReadOnlyList<String> Ip4Addresses
    {
        get
        {
            // ReSharper disable once StringLiteralTypo
            try
            {
                return _Node["addr_info"]!
                       .AsArray()
                       .TryWhere(n => n!["family"]!.GetValue<String>() == "inet")
                       .TrySelect(n => n!["local"]!.GetValue<String>())
                       .ToList();
            }
            catch
            {
                return Array.Empty<String>();
            }
        }
    }

    public String Name
    {
        get
        {
            // ReSharper disable once StringLiteralTypo
            try
            {
                return _Node["ifname"]!.GetValue<String>();
            }
            catch
            {
                return "<NO_NAME>";
            }
        }
    }
    
  

    public async Task<Boolean> AddPointToPoint(String sourceAddress, String destinationAddress)
    {
        var result = await IpCommand
                          .WithArguments($"address add local {sourceAddress} peer {destinationAddress} dev {Name}")
                          .ExecuteAsync();

        return result.ExitCode == 0;
    }
    
    public async Task<Boolean> RemoveAddress(String address)
    {
        var result = await IpCommand
                          .WithArguments($"address del {address} dev {Name}")
                          .ExecuteBufferedAsync();

        return result.ExitCode == 0;
    }


    public  async Task<Boolean> AddRoute(String route)
    {
        var result = await IpCommand
                          .WithArguments($"route add {route} dev {Name}")
                          .ExecuteAsync();

        return result.ExitCode == 0;
    }

    public async Task<Boolean> RemoveRoute(String route)
    {
        var result = await IpCommand
                          .WithArguments($"route del {route} dev {Name}")
                          .ExecuteAsync();

        return result.ExitCode == 0;
    }

  
    public static async Task<IReadOnlyList<Nic>> GetNetworkInterfaces()
    {

        try
        {
             var result = await IpCommand
                               .WithArguments("-details -pretty -json address")
                               .ExecuteBufferedAsync();

             return JsonNode
                   .Parse(result.StandardOutput)!
                   .AsArray()
                   .Where(n => n != null)
                   .Select(n => new Nic(n!))
                   .ToList();
        }
        catch 
        {
            return Array.Empty<Nic>();
        }
    }
    
}