using System.Collections.Concurrent;

namespace ConfigOperator;

public class AddressFileLoader(HardwareAddress addresses)
{
    public void LoadPLC()
    {
        if (!DierctoryHelper.GetAllFiles(Paths.PLCIOListFolder, out List<string>? plcFile) || plcFile is null)
            return;

        foreach (var item in plcFile)
        {
            if (!XmlHelper.DeserializeXml(item, out PLCAddress? output) || output is null)
                continue;

            addresses.PLCAddress = output;
            break;
        }

        if (!DierctoryHelper.GetAllFiles(Paths.PLCChannelIOListFolder, out List<string>? plcChannelFile) || plcChannelFile is null)
            return;

        addresses.PLCChannelsAddresses = [];
        foreach (var item in plcChannelFile)
        {
            if (!XmlHelper.DeserializeXml(item, out List<ChannelAddressPLC>? output) || output is null)
                continue;
            byte mini8Index = output.First().Mini8Index;
            addresses.PLCChannelsAddresses[mini8Index] = [];
            foreach (ChannelAddressPLC channel in output)
            {
                if (channel is null)
                    continue;
                addresses.PLCChannelsAddresses[mini8Index][channel.ChannelIndex] = channel;
            }
        }

    }

    public void Load()
    {
        if (!DierctoryHelper.GetAllFiles(Paths.IOListFolder, out List<string>? hardwareFiles) || hardwareFiles is null)
            return;

        foreach (var item in hardwareFiles)
        {
            if (!XmlHelper.DeserializeXml(item, out AddressSaveXML? output) || output is null)
                continue;
            if (output.Mini8 is null)
                continue;
            if (output.Channels is null)
                continue;

            addresses.Mini8sAddress[output.Mini8.Index] = output.Mini8;
            ConcurrentDictionary<byte, ChannelAddress> channels = [];

            foreach (var channel in output.Channels)
                channels[channel.ChannelIndex] = channel;

            addresses.Mini8ChannelsAddress[output.Mini8.Index] = channels;
        }

    }

    public void Save()
    {
        if (addresses.Mini8ChannelsAddress is null || addresses.Mini8sAddress is null)
            return;
        foreach (var mini8 in addresses.Mini8sAddress)
        {
            AddressSaveXML saveItem = new()
            {
                Mini8 = mini8.Value,
                Channels = [.. addresses.Mini8ChannelsAddress[mini8.Key].Values]
            };
            string path = Path.Combine(Paths.IOListFolder, $"Mini8-{mini8.Value.Index}.xml");
            XmlFileHelper.WriteFile(path, saveItem);
        }
    }

    public void SavePLC()
    {
        if (addresses.PLCAddress is null || addresses.PLCChannelsAddresses is null)
            return;

        string path = Path.Combine(Paths.PLCIOListFolder, $"PLC.xml");
        XmlFileHelper.WriteFile(path, addresses.PLCAddress);

        foreach (var item in addresses.PLCChannelsAddresses)
        {
            List<ChannelAddressPLC> Channels = [];
            Channels.AddRange(item.Value.Values);
            string pathChannel = Path.Combine(Paths.PLCChannelIOListFolder, $"PLC_Channel-{item.Key}.xml");
            XmlFileHelper.WriteFile(pathChannel, Channels);
        }
    }

    public void Fake()
    {
        for (byte mini8Index = 1; mini8Index <= 8; mini8Index++)
        {
            if (mini8Index == 5)
                continue;

            Mini8Address mini8Address = new()
            {
                Index = mini8Index,
                Address = $"192.168.250.{10 + mini8Index}",
                Port = 502
            };

            addresses.Mini8sAddress.TryAdd(mini8Index, mini8Address);

            ConcurrentDictionary<byte, ChannelAddress> channels = [];
            for (byte channelIndex = 1; channelIndex <= 16; channelIndex++)
            {
                ushort move = (ushort)(channelIndex - 1);
                ChannelAddress address = new()
                {
                    Mini8Index = mini8Index,
                    ChannelIndex = channelIndex,

                    PV = (ushort)(15500 + move * 2),
                    WorkingOutput = (ushort)(15532 + move * 2),
                    AutoTuneStatus = (ushort)(15564 + move),
                    AutoTune_P = (ushort)(15596 + move * 2),
                    AutoTune_I = (ushort)(15628 + move * 2),
                    AutoTune_D = (ushort)(15660 + move * 2),

                    SensorBreakAlarm1 = 15692,
                    SensorBreakAlarm2 = 15693,

                    SetPoint = (ushort)(15694 + move * 2),

                    ActiveTuneSet = (ushort)(15726 + move),

                    Running_P = (ushort)(15758 + move * 2),
                    Running_I = (ushort)(15790 + move * 2),
                    Running_D = (ushort)(15822 + move * 2),


                    SetpointUpRate = (ushort)(15860 + move * 2),
                    SetpointDownRate = (ushort)(15892 + move * 2),

                    Caps = (ushort)(5193 + move * 4),
                    Floor = (ushort)(5194 + move * 4),
                    CapsWarning = (ushort)(5195 + move * 4),
                    FloorWarning = (ushort)(5196 + move * 4),

                    Inhibit = (ushort)(15924 + move * 2),
                    ActiveAutoTune = (ushort)(15956 + move * 2),
                };
                channels[channelIndex] = address;
            }
            addresses.Mini8ChannelsAddress[mini8Index] = channels;
        }

    }

    public void FakePLC()
    {
        PLCAddress plcAddress = new()
        {
            IPAddress = "192.168.250.1",
            Port = 9600,
            Interval = 1000,
        };

        addresses.PLCAddress = plcAddress;

        for (byte mini8Index = 1; mini8Index <= 8; mini8Index++)
        {
            if (mini8Index == 5)
                continue;

            ConcurrentDictionary<byte, ChannelAddressPLC> channels = [];
            for (byte channelIndex = 1; channelIndex <= 16; channelIndex++)
            {
                ushort move = (ushort)(channelIndex - 1);
                ChannelAddressPLC address = new()
                {
                    Mini8Index = mini8Index,
                    ChannelIndex = channelIndex,

                    PV = string.Empty,
                    WorkingOutput = string.Empty,
                    AutoTuneStatus = string.Empty,
                    AutoTune_P = string.Empty,
                    AutoTune_I = string.Empty,
                    AutoTune_D = string.Empty,

                    SensorBreakAlarm1 = string.Empty,
                    SensorBreakAlarm2 = string.Empty,

                    SetPoint = string.Empty,

                    ActiveTuneSet = string.Empty,

                    Running_P = string.Empty,
                    Running_I = string.Empty,
                    Running_D = string.Empty,


                    SetpointUpRate = string.Empty,
                    SetpointDownRate = string.Empty,

                    Caps = string.Empty,
                    Floor = string.Empty,
                    CapsWarning = string.Empty,
                    FloorWarning = string.Empty,

                    Inhibit = string.Empty,
                    ActiveAutoTune = string.Empty,
                };
                channels[channelIndex] = address;
            }
            addresses.PLCChannelsAddresses[mini8Index] = channels;
        }

    }
}

public class AddressSaveXML
{
    public Mini8Address? Mini8 { get; set; }
    public List<ChannelAddress>? Channels { get; set; }
}
