using System.Diagnostics;
using System.Text;
using System.Text.Json.Nodes;
using FreneticUtilities.FreneticDataSyntax;

namespace StabilityMatrix.Core.Models.Packages.Config;

public class FdsConfigSharingStrategy : IConfigSharingStrategy
{
    public async Task UpdateAndWriteAsync(
        Stream configStream,
        SharedFolderLayout layout,
        Func<SharedFolderLayoutRule, IEnumerable<string>> pathsSelector,
        IEnumerable<string> clearPaths,
        ConfigSharingOptions options,
        CancellationToken cancellationToken = default
    )
    {
        FDSSection rootSection;
        var initialPosition = configStream.Position;
        var isEmpty = configStream.Length - initialPosition == 0;

        if (!isEmpty)
        {
            try
            {
                // FDSUtility reads from the current position
                using var reader = new StreamReader(configStream, leaveOpen: true);
                var fdsContent = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
                rootSection = new FDSSection(fdsContent);
            }
            catch (Exception ex) // FDSUtility might throw various exceptions on parse errors
            {
                System.Diagnostics.Debug.WriteLine(
                    $"Error deserializing FDS config: {ex.Message}. Treating as new."
                );
                rootSection = new FDSSection();
                isEmpty = true;
            }
        }
        else
        {
            rootSection = new FDSSection();
        }

        // Debug.WriteLine($"-- Current Fds --\n\n{rootSection.SaveToString()}");

        UpdateFdsConfig(layout, rootSection, pathsSelector, clearPaths, options);

        // Reset stream to original position before writing
        configStream.Seek(initialPosition, SeekOrigin.Begin);
        // Truncate the stream
        configStream.SetLength(initialPosition + 0);

        // Save using a StreamWriter to control encoding and leave stream open
        // Use BOM-less UTF-8 encoding !! (FSD not UTF-8 BOM compatible)
        var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
        await using (var writer = new StreamWriter(configStream, encoding, leaveOpen: true))
        {
            // Debug.WriteLine($"-- Saved Fds: --\n\n{rootSection.SaveToString()}");

            await writer
                .WriteAsync(rootSection.SaveToString().AsMemory(), cancellationToken)
                .ConfigureAwait(false);
            await writer.FlushAsync(cancellationToken).ConfigureAwait(false); // Ensure content is written
        }
        await configStream.FlushAsync(cancellationToken).ConfigureAwait(false); // Flush the underlying stream
    }

    private static void UpdateFdsConfig(
        SharedFolderLayout layout,
        FDSSection rootSection,
        Func<SharedFolderLayoutRule, IEnumerable<string>> pathsSelector,
        IEnumerable<string> clearPaths,
        ConfigSharingOptions options
    )
    {
        var rulesByConfigPath = layout.GetRulesByConfigPath();

        // SwarmUI typically stores paths under a "Paths" section
        // Get or create the Paths section
        var pathsSection = rootSection.GetSection("Paths");
        if (pathsSection is null)
        {
            pathsSection = new FDSSection();
            rootSection.Set("Paths", pathsSection); // Add Paths section to the root
        }

        // Keep track of keys managed by the layout to remove old ones
        var allRuleKeys = rulesByConfigPath.Keys.ToHashSet();
        var currentKeysInPathsSection = pathsSection.GetRootKeys(); // Assuming FDS has a way to list keys

        foreach (var (configPath, rule) in rulesByConfigPath)
        {
            var paths = pathsSelector(rule).ToArray();

            // Normalize paths for FDS - likely prefers native OS slashes or forward slashes
            var normalizedPaths = paths.Select(p => p.Replace('/', Path.DirectorySeparatorChar)).ToList();

            if (normalizedPaths.Count > 0)
            {
                // FDS lists are separated by semicolon
                pathsSection.Set(configPath, string.Join(';', normalizedPaths));

                // If FDS supports lists explicitly (e.g., via SetList), use that:
                // pathsSection.SetList(configPath, normalizedPaths);
            }
            else
            {
                // No paths for this rule, remove the key
                // pathsSection.Remove(configPath); // Assuming Remove method exists
            }
        }

        // Remove any keys in the Paths section that are no longer defined by any rule
        /*foreach (var existingKey in currentKeysInPathsSection)
        {
            if (!allRuleKeys.Contains(existingKey))
            {
                pathsSection.Remove(existingKey);
            }
        }*/

        /*// If the Paths section is not empty, add/update it in the root
        if (pathsSection.GetRootKeys().Any()) // Check if the section has content
        {
            rootSection.Set("Paths", pathsSection);
            // rootSection.SetSection("Paths", pathsSection);
        }
        else // Otherwise, remove the empty Paths section from the root
        {
            rootSection.Remove("Paths"); // Assuming Remove method exists for sections too
        }*/
    }
}
