//******************************************************************************************************
//  CIMExportProcessor.cs - Gbtc
//
//  Copyright © 2026, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
//  file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://opensource.org/licenses/MIT
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  01/15/2026 - J. Ritchie Carroll
//       Generated original version of source code.
//
//******************************************************************************************************

namespace DNP3ConfigLoader;

/// <summary>
/// Processes CIM export files to generate device CSV and tag map files.
/// </summary>
public static class CIMExportProcessor
{
    /// <summary>
    /// Processes the CIM export file to create device CSV and tag map files.
    /// </summary>
    public static void ProcessCIMExportFile(ProcessParameters processParams)
    {
        Dictionary<string, CIMDevice> devices = [];

        using (StreamReader reader = new(processParams.Settings.CIMExportFilePath))
        {
            // Skip comment lines and build valid lines list
            List<string> validLines = [];

            while (reader.ReadLine() is { } line)
            {
                if (!line.StartsWith(processParams.Settings.CommentChar))
                    validLines.Add(line);
            }

            if (validLines.Count == 0)
                return;

            // Parse CSV header
            string header = validLines[0];
            string[] columns = Common.ParseCSVLine(header);

            // Process each data row
            for (int i = 1; i < validLines.Count; i++)
            {
                string[] values = Common.ParseCSVLine(validLines[i]);
                Dictionary<string, string?> row = [];

                for (int j = 0; j < columns.Length && j < values.Length; j++)
                    row[columns[j].Trim()] = values[j].Trim();

                // Get RTU Name - skip if empty
                if (!row.TryGetValue("RTU Name", out string? rtuName) || string.IsNullOrWhiteSpace(rtuName))
                    continue;

                // Create device entry if it doesn't exist
                if (!devices.ContainsKey(rtuName))
                {
                    // Get IP address - skip if empty
                    if (!row.TryGetValue("IP address", out string? ipAddress) || string.IsNullOrWhiteSpace(ipAddress))
                        continue;

                    // Get substation name, defaulting to RTU name
                    string substation = row.TryGetValue("Substation", out string? substationValue) && !string.IsNullOrWhiteSpace(substationValue)
                        ? substationValue
                        : rtuName;

                    string endPoint = $"{ipAddress}:{processParams.Settings.DefaultDNP3Port}";

                    devices[rtuName] = new CIMDevice
                    {
                        Name = rtuName,
                        Substation = substation,
                        Connection = endPoint,
                        TagMapFileName = $"{processParams.TagMapDirectory}{rtuName}-tagmap.csv"
                    };
                }

                // Add row to device
                devices[rtuName].Rows.Add(row);
            }
        }

        if (devices.Count == 0)
        {
            Console.WriteLine("     WARNING: No devices found in CIM export file.");
            return;
        }

        Console.WriteLine($"     Found {devices.Count:N0} devices in CIM export file");

        // Create device CSV file with header line
        using (StreamWriter writer = new(processParams.Settings.DeviceCSVFilePath))
        {
            writer.WriteLine("Name,Substation,Connection,TagMapFileName");

            foreach (CIMDevice device in devices.Values)
                writer.WriteLine($"{device.Name},{device.Substation},{device.Connection},{device.TagMapFileName}");
        }

        int count = 0;

        // Create a tag map file for each device
        foreach (CIMDevice device in devices.Values)
        {
            using StreamWriter writer = new(device.TagMapFileName);
            writer.WriteLine("MapType,DNPIndex,TagName,AlternateTag,Scale,Negate,Concatenate,InvertSBit,InvertXBit");

            foreach (Dictionary<string, string?> row in device.Rows)
            {
                // Get telemetry type and map to DNP3 map type
                string telemetryType = row.GetValueOrDefault("Telemetry Type", "")?.Trim().ToLowerInvariant() ?? "";
                string mapType;

                switch (telemetryType)
                {
                    case "analog":
                        mapType = "analog";
                        break;
                    case "discrete":
                        mapType = "binary";
                        break;
                    default:
                        continue; // Skip unsupported telemetry types
                }

                // Get DNP index from PhysicalAddress
                string dnpIndex = row.GetValueOrDefault("PhysicalAddress", "0")?.Trim() ?? "0";

                // Get tag name from "Ouput name Slow" (note: intentional typo in source file)
                string tagName = row.GetValueOrDefault("Ouput name Slow", "")?.Trim() ?? "";

                // Get alternate tag from "Telemetry SCADA CompositeID"
                string alternateTag = row.GetValueOrDefault("Telemetry SCADA CompositeID", "")?.Trim() ?? "";

                // Get scale (default to 1.0)
                string scaleStr = row.GetValueOrDefault("Scale", "1.0")?.Trim() ?? "";
                string scale = string.IsNullOrEmpty(scaleStr) ? "1.0" : scaleStr;

                // Get negate flag
                string negateStr = row.GetValueOrDefault("Negate", "FALSE")?.Trim() ?? "";
                string negate = string.IsNullOrEmpty(negateStr) ? "FALSE" : negateStr;

                // Get concatenate flag
                string concatenateStr = row.GetValueOrDefault("Concatenate", "FALSE")?.Trim() ?? "";
                string concatenate = string.IsNullOrEmpty(concatenateStr) ? "FALSE" : concatenateStr;

                // Get InvertSBit flag
                string invertSBitStr = row.GetValueOrDefault("InvertSBit", "FALSE")?.Trim() ?? "";
                string invertSBit = string.IsNullOrEmpty(invertSBitStr) ? "FALSE" : invertSBitStr;

                // Get InvertXBit flag
                string invertXBitStr = row.GetValueOrDefault("InvertXBit", "FALSE")?.Trim() ?? "";
                string invertXBit = string.IsNullOrEmpty(invertXBitStr) ? "FALSE" : invertXBitStr;

                writer.WriteLine($"{mapType},{dnpIndex},{tagName},{alternateTag},{scale},{negate},{concatenate},{invertSBit},{invertXBit}");
            }

            count++;

            if (count % 25 == 0)
                Console.WriteLine($"     Processed {count:N0} devices...");
        }

        Console.WriteLine($"     Processed {count:N0} devices and created tag map files in \"{processParams.TagMapDirectory}\" directory");
    }
}
