// dotnet publish BmsTunnel.csproj -c Release -r linux-arm -p:PublishSingleFile=true --self-contained true && \
// rsync -av bin/Release/net6.0/linux-arm/publish/ root@10.2.1.6:/home/root/tunnel && clear && \
// ssh root@10.2.1.6 /home/root/tunnel/BmsTunnel

using System.Net;
using InnovEnergy.Lib.Utils;
using static System.String;

namespace InnovEnergy.BmsTunnel;

public static class Program
{
    private const Byte DefaultNode = 2;

    public static async Task<Int32> Main(String[] args)
    {
        var connection = await ConnectToBms(args.FirstOrDefault());

        if (connection is null)
            return 2;
        
        Console.WriteLine("\nstarting BMS tunnel\n");
        
        var path = $"/dev/{tty}";
        if (host != null) 
            path = $"root@{host}" + path;
        
        var node = connection.Nodes.Any() 
                 ? connection.Nodes.First() 
                 : DefaultNode;
        
        using var tunnel = new BmsTunnel(path, node);

        ExplainNode();
        ExplainNodes();
        ExplainExit();
        
        Console.WriteLine("");
        
        ListNodes();

        while (true)
        {
            Console.WriteLine("");
            Console.Write($"node{tunnel.Node}> ");

            var cmd = Console.ReadLine()?.ToUpper().Trim();

            if (IsNullOrEmpty(cmd))
                continue;

            if (cmd.StartsWith("/"))
            {
                var exit = ProcessLocalCommand(cmd);
                if (exit)
                    break;
                continue;
            }

            tunnel.SendCommand(cmd).Skip(1).ForEach(Console.WriteLine);
        }
        
        
        Boolean ProcessLocalCommand(String cmd)
        {
            cmd = cmd.TrimStart('/').Trim();
            
            if (cmd == "EXIT") 
                return true;

            if (cmd == "NODES") 
                ListNodes();
            else if (cmd.StartsWith("NODE ")) 
                ChangeNode(cmd);
            else 
                Console.WriteLine("unrecognized command");

            return false;
        }

        return 0;
        
        void ListNodes()
        {
            if(nodes.Count >= 250)
                return;
            
            nodes.Aggregate("available nodes:", (a, b) => $"{a} {b}")
                 .Apply(Console.WriteLine);
        }

        void ChangeNode(String cmd)
        {
            var ndStr = cmd[5..].Trim();
            
            if (!Byte.TryParse(ndStr, out var newNode))
            {
                ExplainNode();
                return;
            }

            if (!nodes.Contains(newNode))
            {
                Console.WriteLine(newNode + " is not available");
                ListNodes();
                return;
            }

            tunnel.Node = newNode;
        }
    }

    private static async Task<BatteryConnection?> ConnectToBms(String? hostName)
    {
        if (hostName is null)
            return new BatteryConnection();

        var host = new SshHost(hostName);

        if (await host.Ping())
            return await BatteryConnection.Connect(host);
        
        $"Cannot connect to {hostName}".WriteLine(ConsoleColor.Red);

        return null;
    }


    private static void ExplainExit()  => Console.WriteLine("/exit       exit bms cli");
    private static void ExplainNodes() => Console.WriteLine("/nodes      list available nodes");
    private static void ExplainNode()  => Console.WriteLine("/node <nb>  change to node number <nb>");


}