using ConfigOperator;
using GeneralData;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using TemperatureConfigFile;
using Universal;

namespace ToMcFile;

internal class Program
{
    static void Main(string[] args)
    {
    Start:
        string? path;
        Console.WriteLine("Please drag file into console and press <Enter>");
        path = Console.ReadLine();
        path = path?.Trim('"');
        if (string.IsNullOrEmpty(path) || !File.Exists(path))
        {
            Console.WriteLine("File Not Exist");
            goto Start;
        }

        Console.WriteLine("Input Numerator:");
        string? numeratorString = Console.ReadLine();
        if (string.IsNullOrEmpty(numeratorString) || !int.TryParse(numeratorString, out int numerator) || numerator < 0)
        {
            Console.WriteLine("numerator Error");
            goto Start;
        }

        Console.WriteLine("Input Denominator:");
        string? denominatorString = Console.ReadLine();
        if (string.IsNullOrEmpty(denominatorString) || !int.TryParse(denominatorString, out int denominator) || denominator < 0)
        {
            Console.WriteLine("denominator Error");
            goto Start;
        }

        Dictionary<string, Dictionary<int, Dictionary<int, string>>> sheet_row_colum = ExcelReader.Read(path, 1);

        foreach (var row_colum in sheet_row_colum)
        {
            ConfigSaveXML configSaveXML = new()
            {
                EditTime = DateTime.Now,
                Editor = "Undefined",
                Description = "Undefined",
                Mini8Configs = []
            };

            Dictionary<byte, Mini8ConfigXML> mini8Configs = [];
            foreach (var colum in row_colum.Value)
            {
                if (!byte.TryParse(colum.Value[0], out byte mini8Index))
                    continue;

                if (!mini8Configs.TryGetValue(mini8Index, out Mini8ConfigXML? mini8Config))
                {
                    mini8Config = new()
                    {
                        Index = mini8Index,
                        ChannelConfig = []
                    };
                    mini8Configs[mini8Index] = mini8Config;
                }

                ChannelConfig channel = GetChannelConfig(colum.Value, numerator, denominator);
                channel.CapsWarning = (channel.Caps + channel.SetPoint) / 2;
                channel.FloorWarning = (channel.Floor + channel.SetPoint) / 2;
                mini8Config.ChannelConfig!.Add(channel);
            }
            configSaveXML.Mini8Configs.AddRange(mini8Configs.Values);

            string outputPath = Path.Combine(Path.GetDirectoryName(path)!, $"{row_colum.Key}.mc");
            XmlFileHelper.WriteFile(outputPath, configSaveXML);
        }
        goto Start;
    }

    private static ChannelConfig GetChannelConfig(Dictionary<int, string> channel, int numerator, int denominator)
    {
        string[] content = [.. channel.Values];
        ChannelConfig config = new()
        {
            Index = byte.Parse(content[1])
        };

        if (float.TryParse(content[2], out float setPoint))
        {
            Console.WriteLine(setPoint);
            if (setPoint > 60)
                config.SetPoint = setPoint / denominator * numerator;
            else
                config.SetPoint = setPoint;
        }
        if (numerator != 1 || denominator != 1)
        {
            config.Floor = config.SetPoint - 10;
            config.Caps = config.SetPoint + 10;
        }
        else
        {
            if (float.TryParse(content[4], out float floor))
                config.Floor = floor;
            if (float.TryParse(content[5], out float caps))
                config.Caps = caps;
        }

        if (float.TryParse(content[6], out float p))
            config.Running_P = p;
        if (float.TryParse(content[7], out float i))
            config.Running_I = i;
        if (float.TryParse(content[8], out float d))
            config.Running_D = d;

        config.ActiveTuneSet = ActiveTuneSet.Running;

        config.Inhibit = content[9] switch
        {
            "Enable" => Inhibit.Enable,
            _ => Inhibit.Disable
        };

        config.ChannelMode = content[2] switch
        {
            "moni" => ChannelMode.Monitor,
            "MONI." => ChannelMode.Monitor,
            _ => ChannelMode.Control,
        };

        if (config.Inhibit == Inhibit.Disable)
            config.ChannelMode = ChannelMode.UnUsed;

        if (content.Length < 11)
            return config;

        if (float.TryParse(content[10], out float upRate))
            config.SetpointUpRate = upRate;

        if (float.TryParse(content[11], out float downRate))
            config.SetpointDownRate = downRate;


        return config;
    }

    private static ChannelConfig GetChannelConfig(Dictionary<int, string> channel)
    {
        string[] content = [.. channel.Values];
        ChannelConfig config = new()
        {
            Index = byte.Parse(content[1])
        };

        if (float.TryParse(content[2], out float setPoint))
            config.SetPoint = setPoint;
        if (float.TryParse(content[4], out float floor))
            config.Floor = floor;
        if (float.TryParse(content[5], out float caps))
            config.Caps = caps;

        if (float.TryParse(content[6], out float p))
            config.Running_P = p;
        if (float.TryParse(content[7], out float i))
            config.Running_I = i;
        if (float.TryParse(content[8], out float d))
            config.Running_D = d;

        config.ActiveTuneSet = ActiveTuneSet.Running;

        config.Inhibit = content[9] switch
        {
            "Enable" => Inhibit.Enable,
            _ => Inhibit.Disable
        };

        config.ChannelMode = content[2] switch
        {
            "moni" => ChannelMode.Monitor,
            _ => ChannelMode.Control,
        };

        if (config.Inhibit == Inhibit.Disable)
            config.ChannelMode = ChannelMode.UnUsed;

        if (content.Length < 11)
            return config;

        if (float.TryParse(content[10], out float upRate))
            config.SetpointUpRate = upRate;

        if (float.TryParse(content[11], out float downRate))
            config.SetpointDownRate = downRate;

        return config;
    }
}

public class ExcelReader
{
    public static Dictionary<string, Dictionary<int, Dictionary<int, string>>> Read(string filePath, int startRow)
    {
        Dictionary<string, Dictionary<int, Dictionary<int, string>>> sheets = [];

        using FileStream file = new(filePath, FileMode.Open, FileAccess.Read);

        for (int i = 0; ; i++)
        {
            ISheet sheet;
            try
            {
                sheet = new XSSFWorkbook(file).GetSheetAt(i);
                if (sheet is null)
                    break;
            }
            catch
            {
                break;
            }
            Dictionary<int, Dictionary<int, string>> contents = [];
            sheets[sheet.SheetName] = contents;

            for (int row = startRow; row <= sheet.LastRowNum; row++)
            {
                if (sheet.GetRow(row) is not IRow currentRow)
                    continue;
                contents[row] = [];
                for (int colum = 0; colum < currentRow.LastCellNum; colum++)
                {
                    ICell cell = currentRow.GetCell(colum);
                    contents[row][colum] = cell?.ToString() ?? string.Empty;
                }
            }
        }
        return sheets;
    }
}
