using InnovEnergy.Lib.SrcGen.Trees;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
using Sawmill;

namespace InnovEnergy.Lib.SrcGen;



using S = IEnumerable<String>;

//public record Node(String Prefix, Node Children);

public static class Program
{
    
    private const String GeneratedCodeMsg = "// This file has been automatically generated, do not edit!\n\n";

    public static async Task Main(String[] args)
    {
        //Nest();

        var projectPath = args.FirstOrDefault() 
                          ?? "/home/eef/sync/work/Code/innovenergy/git/csharp/Lib/Devices/Battery48TL/Battery48TL.csproj";

        if (projectPath is null)
            throw new ArgumentException(nameof(projectPath));

        MSBuildLocator.RegisterDefaults(); // WTF
        
        using var workspace = MSBuildWorkspace.Create();
        await workspace.OpenProjectAsync(projectPath);
        
        var solution    = workspace.CurrentSolution;
        var project     = solution.Projects.Single(p => p.FilePath == projectPath);
        var compilation = await project.GetCompilationAsync();

        if (compilation is null)
            throw new Exception($"Project {projectPath} failed to build!");

        await GenerateAttributes.Generate(project, compilation);
        await NestProperties.Generate(project, compilation);
    }


    private static void Nest()
    {
        var strings = new[]
        {
            "AcCurrent",
            "AcVoltage",
            "AcPowerReactive",
            "AcPowerActive",
            "DcCurrent",
            "DcVoltage",
            "Temperature",
            "Soc"
        };


        var tree1 = new ForwardTree<String>("", strings.Select(s => new ForwardTree<String>(s)).ToList());

        static ForwardTree<String> GroupByPrefix(ForwardTree<String> tree)
        {
            var newChildren = tree
                .Children
                .Where(s => s.Node.Length > 0)
                .GroupBy(s => s.Node[..1], s => new ForwardTree<String>(s.Node[1..]))
                .Select(g => GroupByPrefix(new ForwardTree<String>(g.Key, g.ToList())))
                .ToList();

            return newChildren.Count == 0
                ? tree // leaf
                : new ForwardTree<String>(tree.Node, newChildren);
        }


        ForwardTree<String> ConcatUnaryNodes(ForwardTree<String> tree)
        {
            return tree.Children.Count == 1 && tree.Children[0] is var child
                ? new ForwardTree<String>(tree.Node + child.Node, child.Children)
                : tree;
        }

        var tree2 = tree1.Rewrite(GroupByPrefix);
        var tree3 = tree2.Rewrite(ConcatUnaryNodes);


        Console.WriteLine(tree1);
        Console.WriteLine("\n======\n");
        Console.WriteLine(tree2);
        Console.WriteLine("\n======\n");
        Console.WriteLine(tree3);
    }


    private static Func<ForwardTree<String>, ForwardTree<String>> RewriteTree(Func<ForwardTree<String>, ForwardTree<String>> rec)
            => tree
            => tree.RewriteIter(n =>
            {
                if (n.Children.Count == 0 || n.Children.SelectMany(c => c.Children).Any())
                    return n;

                var groups = n
                    .Children
                    .Where(s => s.Node.Length > 0)
                    .GroupBy(s => s.Node[..1], s => rec(new ForwardTree<String>(s.Node[1..])))
                    .Select(g => new ForwardTree<String>(g.Key, g.ToList()))
                    .ToList();

                if (groups.Count == 0)
                    return n;

                return new ForwardTree<String>(n.Node, groups);
            });
}



        
        // static IReadOnlyList<StringTree> GetChildren(IEnumerable<String> strings)
        // {
        //     return strings
        //           .Where(s => s.Length > 0)
        //           .GroupBy(s => s[..1], s => s[1..])
        //           .Select(l =>
        //           {
        //               var children = GetChildren(l);
        //               return children.Count == 1
        //                   ? new StringTree(l.Key + children[0].Node, children[0].Children)
        //                   : new StringTree(l.Key, children);
        //           })
        //           .ToList();
        // }
        //var t2 = new Tree<(String prefix, String[] strings)>(stringNode, );
        
        // var strs = Func<S, S> (Func<S, S> rec) 
        //          => S (ss) 
        //          => ss.Where(s => s.Length > 0)
        //              .GroupBy(s => s[..1], s => s[1..])
        //              .SelectMany(g=> !g.Any() ? new[] { g.Key } : rec(g))
        //              
        //                                                 ;
        //
        // var g = Func<Int32, Int32> (Func<Int32, Int32> h) 
        //      => Int32 (Int32 m) 
        //      => m > 1 ? h(m - 1) + h(m - 2) : m;
        //
        // var fib = Combinator.Y(g);
        // var fib2 = Combinator.Y(strs);
        //
        // var y = fib(5);
        // var x = fib2(strings).ToList();
        //