using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Protocols.Modbus.Channels;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
using InnovEnergy.Lib.Utils;

namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;

public class TruConvertDcDcDevices
{
    private readonly ModbusDevice<SystemControlRegisters>  _SystemControl;
    private readonly IEnumerable<ModbusDevice<DcDcRecord>> _DcDcs;

    public TruConvertDcDcDevices(String hostname, UInt16 port) : this(new TcpChannel(hostname, port))
    {
    }
    
    public TruConvertDcDcDevices(Channel transport)
    {
        var modbusClient = new ModbusTcpClient(transport, 0);

        _SystemControl = new ModbusDevice<SystemControlRegisters>(modbusClient);

        _DcDcs = Enumerable
                .Range(1, Byte.MaxValue - 1)
                .Memoize(CreateDcDc);

        ModbusDevice<DcDcRecord> CreateDcDc(Int32 i)
        {
            var mb = new ModbusTcpClient(transport, (Byte)i);
            return new ModbusDevice<DcDcRecord>(mb);
        }
    }


    public DcDcDevicesRecord Read()
    {
        
        try
        {
            var scStatus = _SystemControl.Read();
            var n = scStatus.NumberOfConnectedSlaves;

            var dcDcRecords = _DcDcs
                              .Take(n)
                              .Select(dcdc => dcdc.Read())
                              .ToArray(n);

            return new DcDcDevicesRecord(scStatus, dcDcRecords);
        }
        catch 
        {
            "Failed to read DCDC data".WriteLine();
            return new DcDcDevicesRecord(null, Array.Empty<DcDcRecord>());
        }
    }
    
    public void Write(DcDcDevicesRecord r)
    {
        if (r.SystemControl is not null)
            _SystemControl.Write(r.SystemControl); // must run BEFORE the attached devices
        
        foreach (var (ctrl, device) in r.Devices.Zip(_DcDcs))
        {
            try
            {
                device.Write(ctrl);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                // TODO: log
            }
        }
    }
    
    
}