using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Shapes;
using Size = System.Windows.Size;

namespace Nodify.Calculator
{
    public static class OperationFactory
    {

        public static List<OperationInfoViewModel> GetSystemNodes()
        {
            List<OperationInfoViewModel> systemNodes = new List<OperationInfoViewModel>();

            var copynode = new OperationInfoViewModel()
            {
                Title = "COPY",
                Type = OperationType.System,
                sysOp = SystemOperations.COPY,
                IsFlowNode = false,
            };
            copynode.Input.Add("");

            var begin = new OperationInfoViewModel()
            {
                Title = "Begin",
                Type = OperationType.System,
                sysOp = SystemOperations.BEGIN,
                IsFlowNode = true
            };
            begin.Output.Add("");

            var ending = new OperationInfoViewModel()
            {
                Title = "End",
                Type = OperationType.System,
                sysOp = SystemOperations.END,
                IsFlowNode = true
            };
            ending.Input.Add("");

            var debugAndCreateModels = new OperationInfoViewModel()
            {
                Title = "Debug & Create Model",
                Type = OperationType.System,
                sysOp = SystemOperations.DEBUG_AND_CREATE_MODEL,
                IsFlowNode = true
            };
            debugAndCreateModels.Input.Add("");
            debugAndCreateModels.Output.Add("");

            var jsonParseNode = new OperationInfoViewModel()
            {
                Title = "Parse Json",
                Type = OperationType.System,
                sysOp = SystemOperations.PARSEJSON,
                IsFlowNode = false
            };
            jsonParseNode.Input.Add("");
            jsonParseNode.Output.Add("");

            var splitNode = new OperationInfoViewModel()
            {
                Title = "Split",
                Type = OperationType.System,
                sysOp = SystemOperations.SPLIT,
                IsFlowNode = false
            };
            splitNode.Input.Add("");
            // No default output - outputs are added dynamically on connection

            var takeNode = new OperationInfoViewModel()
            {
                Title = "TAKE",
                Type = OperationType.System,
                sysOp = SystemOperations.TAKE,
                IsFlowNode = false
            };
            takeNode.Input.Add("List");

            var authNode = new OperationInfoViewModel()
            {
                Title = "Auth",
                Type = OperationType.System,
                sysOp = SystemOperations.AUTH,
                IsFlowNode = true
            };
            authNode.Input.Add("Base URL");
            authNode.Input.Add("Auth Type");
            authNode.Input.Add("Token");
            authNode.Input.Add("API Key");
            authNode.Input.Add("Username");
            authNode.Input.Add("Password");

            var debugNode = new OperationInfoViewModel()
            {
                Title = "Debug",
                Type = OperationType.System,
                sysOp = SystemOperations.DEBUG,
                IsFlowNode = true
            };
            debugNode.Input.Add("Value");

            systemNodes.Add(authNode);
            systemNodes.Add(copynode);
            systemNodes.Add(debugNode);
            systemNodes.Add(begin);
            systemNodes.Add(ending);
            systemNodes.Add(debugAndCreateModels);
            systemNodes.Add(jsonParseNode);
            systemNodes.Add(splitNode);
            systemNodes.Add(takeNode);
            return systemNodes;
        }

        public static List<OperationInfoViewModel> GetOperationsInfo(Type container)
        {
            List<OperationInfoViewModel> result = new List<OperationInfoViewModel>();

            foreach (var method in container.GetMethods())
            {
                if (method.IsStatic)
                {
                    OperationInfoViewModel op = new OperationInfoViewModel
                    {
                        Title = method.Name
                    };

                    var attr = method.GetCustomAttribute<OperationAttribute>();
                    var para = method.GetParameters();

                    bool generateInputNames = true;

                    op.Type = OperationType.Normal;

                    if (para.Length == 2)
                    {
                        var delType = typeof(Func<double, double, double>);
                        var del = (Func<double, double, double>)Delegate.CreateDelegate(delType, method);

                        op.Operation = new BinaryOperation(del);
                    }
                    else if (para.Length == 1)
                    {
                        if (para[0].ParameterType.IsArray)
                        {
                            op.Type = OperationType.Expando;

                            var delType = typeof(Func<double[], double>);
                            var del = (Func<double[], double>)Delegate.CreateDelegate(delType, method);

                            op.Operation = new ParamsOperation(del);
                            op.MaxInput = int.MaxValue;
                        }
                        else
                        {
                            var delType = typeof(Func<double, double>);
                            var del = (Func<double, double>)Delegate.CreateDelegate(delType, method);

                            op.Operation = new UnaryOperation(del);
                        }
                    }
                    else if (para.Length == 0)
                    {
                        var delType = typeof(Func<double>);
                        var del = (Func<double>)Delegate.CreateDelegate(delType, method);

                        op.Operation = new ValueOperation(del);
                    }

                    if (attr != null)
                    {
                        op.MinInput = attr.MinInput;
                        op.MaxInput = attr.MaxInput;
                        generateInputNames = attr.GenerateInputNames;
                    }
                    else
                    {
                        op.MinInput = (uint)para.Length;
                        op.MaxInput = (uint)para.Length;
                    }

                    foreach (var param in para)
                    {
                        op.Input.Add(generateInputNames ? param.Name : null);
                    }

                    for (int i = op.Input.Count; i < op.MinInput; i++)
                    {
                        op.Input.Add(null);
                    }
                    op.Output.Add("");
                    result.Add(op);
                }
            }

            return result;
        }

        public static OperationViewModel GetOperation(OperationInfoViewModel info)
        {
            var input = info.Input.Select(i => new ConnectorViewModel
            {
                Title = i
            });

            switch (info.Type)
            {
                case OperationType.Expression:
                    var eo = new ExpressionOperationViewModel
                    {
                        Title = info.Title,
                        Operation = info.Operation,
                        Expression = "1 + sin {a} + cos {b}"
                    };
                    eo.Output.Add(new ConnectorViewModel { ConnectorColor = Color.DodgerBlue });
                    return eo;
                case OperationType.Calculator:
                    return new CalculatorOperationViewModel
                    {
                        Title = info.Title,
                        Operation = info.Operation,
                    };

                case OperationType.Expando:
                    var o = new ExpandoOperationViewModel
                    {
                        MaxInput = info.MaxInput,
                        MinInput = info.MinInput,
                        Title = info.Title,
                        Operation = info.Operation
                    };
                    o.Output.Add(new ConnectorViewModel { ConnectorColor = Color.DodgerBlue });
                    foreach (var ei in input) { ei.ConnectorColor = Color.DodgerBlue; }
                    o.Input.AddRange(input);
                    return o;

                case OperationType.Group:
                    return new OperationGroupViewModel
                    {
                        Title = info.Title,
                    };

                case OperationType.Graph:
                    return new OperationGraphViewModel
                    {
                        Title = info.Title,
                        DesiredSize = new Size(420, 250)
                    };

                case OperationType.API:
                    var _o = new APIOperationViewModel
                    {
                        Title = info.Title,
                        OperationType = info.OPType.ToUpper(),
                        ResponseModelClassName = info.ResponseModelClassName ?? string.Empty
                    };
                    var connectorViewModel = new ConnectorViewModel()
                    {
                        Title = "",
                        Shape = ConnectorShape.Triangle
                    };
                    var connectorViewModel2 = new ConnectorViewModel()
                    {
                        Title = "",
                        Shape = ConnectorShape.Triangle,
                        IsInput = false
                    };
                    _o.Output.Add(connectorViewModel2);

                    // Add typed response output based on ResponseModelClassName
                    if (!string.IsNullOrEmpty(info.ResponseModelClassName))
                    {
                        var responseClassName = info.ResponseModelClassName;
                        bool isList = responseClassName.StartsWith("List<") && responseClassName.EndsWith(">");
                        var innerType = isList ? responseClassName.Substring(5, responseClassName.Length - 6) : responseClassName;

                        // Square connector for model output
                        _o.Output.Add(new ConnectorViewModel
                        {
                            Title = responseClassName,
                            IsInput = false,
                            Shape = ConnectorShape.Square,
                            ConnectorColor = Color.MediumPurple,
                            DataType = responseClassName
                        });
                    }
                    else
                    {
                        // Default: generic object output
                        _o.Output.Add(new ConnectorViewModel
                        {
                            Title = "Response",
                            IsInput = false,
                            Shape = ConnectorShape.Circle,
                            ConnectorColor = Color.LimeGreen,
                            DataType = "object"
                        });
                    }

                    _o.Input.Add(connectorViewModel);
                    foreach (var item in input)
                    {
                        item.ConnectorColor = Color.LimeGreen;
                        _o.Input.Add(item);
                    }
                    return _o;
                case OperationType.System:
                    if (info.sysOp == SystemOperations.FUNCTION)
                    {
                        var funcOp = new FunctionOperationViewModel
                        {
                            Title = info.Title,
                            FunctionName = info.Title
                        };
                        // Add flow connectors (triangle)
                        var funcFlowIn = new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle };
                        var funcFlowOut = new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false };
                        funcOp.Input.Add(funcFlowIn);
                        funcOp.Output.Add(funcFlowOut);

                        // Configure typed input/output parameters
                        funcOp.ConfigureParameters(info.FunctionInputs, info.FunctionOutputs);
                        return funcOp;
                    }

                    if (info.sysOp == SystemOperations.DEBUG)
                    {
                        var debugOp = new SystemOperationViewModel
                        {
                            Title = info.Title,
                            SystemOperationType = SystemOperations.DEBUG
                        };
                        // Flow connectors
                        debugOp.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
                        debugOp.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });
                        // Data input
                        foreach (var inp in input)
                        {
                            inp.ConnectorColor = Color.LimeGreen;
                            debugOp.Input.Add(inp);
                        }
                        return debugOp;
                    }

                    if (info.sysOp == SystemOperations.AUTH)
                    {
                        var authOp = new AuthOperationViewModel
                        {
                            Title = info.Title,
                            SystemOperationType = SystemOperations.AUTH
                        };
                        // Add flow connectors (triangle)
                        var flowIn = new ConnectorViewModel()
                        {
                            Title = "",
                            Shape = ConnectorShape.Triangle
                        };
                        var flowOut = new ConnectorViewModel()
                        {
                            Title = "",
                            Shape = ConnectorShape.Triangle,
                            IsInput = false
                        };
                        authOp.Input.Add(flowIn);
                        authOp.Output.Add(flowOut);
                        // Add data input connectors
                        foreach (var inp in input)
                        {
                            inp.ConnectorColor = Color.Orange;
                            authOp.Input.Add(inp);
                        }
                        return authOp;
                    }

                    if (info.sysOp == SystemOperations.TAKE)
                    {
                        var takeOp = new TakeOperationViewModel
                        {
                            Title = info.Title,
                            SystemOperationType = SystemOperations.TAKE
                        };

                        // List input — accepts any shape but only list/array DataTypes
                        foreach (var item in input)
                        {
                            item.Shape = ConnectorShape.Circle;
                            item.ConnectorColor = Color.White;
                            item.IsCopyConnector = true;
                            item.IsTakeListConnector = true;
                            item.Title = "List";
                            takeOp.Input.Add(item);
                        }

                        // Nth index input (int type)
                        var nthConnector = new ConnectorViewModel
                        {
                            Title = "Nth",
                            Shape = ConnectorShape.Circle,
                            ConnectorColor = ConnectorViewModel.GetColorForType("int"),
                            DataType = "int"
                        };
                        takeOp.NthConnector = nthConnector;
                        takeOp.Input.Add(nthConnector);

                        return takeOp;
                    }

                    var sysOp = new SystemOperationViewModel
                    {
                        Title = info.Title,
                        SystemOperationType = info.sysOp
                    };

                    if (info.sysOp == SystemOperations.COPY)
                    {
                        sysOp.Title = info.Title;
                        // Universal input — accepts any shape. Starts with no outputs.
                        foreach (var item in input)
                        {
                            item.Shape = ConnectorShape.Circle;
                            item.ConnectorColor = Color.White;
                            item.IsCopyConnector = true;
                            sysOp.Input.Add(item);
                        }
                        return sysOp;
                    }

                    if (info.sysOp == SystemOperations.SPLIT)
                    {
                        sysOp.Title = info.Title;
                        // Square input to accept model/class objects
                        foreach (var item in input)
                        {
                            item.Shape = ConnectorShape.Square;
                            item.ConnectorColor = Color.MediumPurple;
                            sysOp.Input.Add(item);
                        }
                        return sysOp;
                    }

                    if (info.sysOp == SystemOperations.GET_SET && info.IsModelNode && !info.IsSimpleVariable)
                    {
                        if (info.Title == "GET")
                        {
                            info.Output.Add("");
                            info.IsFlowNode = false;
                        }
                        else if (info.Title == "SET")
                        {
                            info.Input.Add("");
                            var customModelDir = System.IO.Path.Combine(ProjectManager.ProjectDirectory, "CustomModels");
                            Directory.CreateDirectory(customModelDir);
                            var flpath = System.IO.Path.Combine(customModelDir, info.ClassName + ".cs");
                            if (File.Exists(flpath))
                            {
                                var fileContent = File.ReadAllText(flpath);
                                var properties = GetPropertiesFromClass(fileContent);

                                Console.WriteLine("Properties found:");
                                foreach (var property in properties)
                                {
                                    Console.WriteLine($"Property Name: {property.Name}, Type: {property.Type}");
                                }

                                info.IsFlowNode = true;

                                // Build the node with flow connectors first
                                var flTitle = $"{info.Title} {info.ClassName}";
                                sysOp.Title = flTitle;

                                // Flow connectors
                                sysOp.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
                                sysOp.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });

                                // Input: Square connector for the class object
                                foreach (var item in input)
                                {
                                    item.Shape = ConnectorShape.Square;
                                    item.ConnectorColor = Color.MediumPurple;
                                    sysOp.Input.Add(item);
                                }

                                // Outputs: Circle connectors per property, colored by type
                                foreach (var property in properties)
                                {
                                    var propColor = ConnectorViewModel.GetColorForType(property.Type);
                                    var propType = property.Type.ToLower();
                                    sysOp.Output.Add(new ConnectorViewModel
                                    {
                                        Title = $"{property.Name} ({property.Type})",
                                        IsInput = false,
                                        Shape = ConnectorShape.Circle,
                                        ConnectorColor = propColor,
                                        DataType = propType
                                    });
                                }

                                return sysOp;
                            }

                            info.IsFlowNode = true;
                        }
                        var flTitle2 = $"{info.Title} {info.ClassName}";
                        sysOp.Title = flTitle2;
                    }

                    if (info.sysOp == SystemOperations.GET_SET && info.IsSimpleVariable)
                    {
                        var varLabel = $"{info.Title} {info.ClassName} ({info.VariableType})";
                        sysOp.Title = varLabel;
                        var varType = info.VariableType.ToLower();
                        var varColor = ConnectorViewModel.GetColorForType(varType);

                        if (info.Title == "GET")
                        {
                            // GET variable: output the value, no flow needed
                            info.IsFlowNode = false;

                            // Flow connectors not needed, output connector with type color
                            sysOp.Output.Add(new ConnectorViewModel
                            {
                                Title = "Value",
                                IsInput = false,
                                Shape = ConnectorShape.Circle,
                                ConnectorColor = varColor,
                                DataType = varType
                            });

                            return sysOp;
                        }
                        else if (info.Title == "SET")
                        {
                            // SET variable: input connector for the value, flow node
                            info.IsFlowNode = true;

                            // Flow connectors
                            sysOp.Input.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle });
                            sysOp.Output.Add(new ConnectorViewModel { Title = "", Shape = ConnectorShape.Triangle, IsInput = false });

                            // Data input with type color
                            sysOp.Input.Add(new ConnectorViewModel
                            {
                                Title = "Value",
                                Shape = ConnectorShape.Circle,
                                ConnectorColor = varColor,
                                DataType = varType
                            });

                            return sysOp;
                        }
                    }

                    if (info.sysOp != SystemOperations.BEGIN &&
                        info.sysOp != SystemOperations.END &&
                        info.IsFlowNode)
                    {
                        var flowinputnode = new ConnectorViewModel()
                        {
                            Title = "",
                            Shape = ConnectorShape.Triangle
                        };
                        var flowoutputnode = new ConnectorViewModel()
                        {
                            Title = "",
                            Shape = ConnectorShape.Triangle,
                            IsInput = false
                        };
                        sysOp.Input.Add(flowinputnode);
                        sysOp.Output.Add(flowoutputnode);
                    }
                    // Determine connector shape & color based on system operation type
                    ConnectorShape dataShape;
                    System.Drawing.Color dataColor;
                    if (info.IsModelNode && !info.IsSimpleVariable)
                    {
                        dataShape = ConnectorShape.Square;
                        dataColor = Color.MediumPurple;
                    }
                    else if (info.IsSimpleVariable)
                    {
                        dataShape = ConnectorShape.Circle;
                        dataColor = Color.LightGreen;
                    }
                    else
                    {
                        dataShape = ConnectorShape.Circle;
                        dataColor = Color.Cyan;
                    }

                    foreach (var item in info.Output)
                    {
                        var isBeginEnd = info.sysOp == SystemOperations.BEGIN || info.sysOp == SystemOperations.END;
                        var out1 = new ConnectorViewModel()
                        {
                            Title = string.IsNullOrEmpty(item) ? "" : item,
                            IsInput = false,
                            Shape = isBeginEnd ? ConnectorShape.Triangle : dataShape,
                            ConnectorColor = isBeginEnd ? Color.DarkRed : dataColor,
                        };
                        sysOp.Output.Add(out1);
                    }
                    foreach (var item in input)
                    {
                        var isBeginEnd = info.sysOp == SystemOperations.BEGIN || info.sysOp == SystemOperations.END;
                        item.Shape = isBeginEnd ? ConnectorShape.Triangle : dataShape;
                        item.ConnectorColor = isBeginEnd ? Color.DarkRed : dataColor;
                        sysOp.Input.Add(item);
                    }
                    return sysOp;
                default:
                    {
                        var op = new OperationViewModel
                        {
                            Title = info.Title,
                            Operation = info.Operation,
                        };
                        var ccv = new ConnectorViewModel()
                        {
                            IsInput = false,
                            Shape = ConnectorShape.Circle,
                            Title = "",
                            ConnectorColor = Color.DodgerBlue
                        };
                        op.Output.Add(ccv);
                        foreach (var di in input) { di.ConnectorColor = Color.DodgerBlue; }
                        op.Input.AddRange(input);
                        return op;
                    }
            }
        }

        public static List<CustomProperty> GetPropertiesFromClassPublic(string classContent) => GetPropertiesFromClass(classContent);

        static List<CustomProperty> GetPropertiesFromClass(string classContent)
        {
            // Parse the C# class content using Roslyn
            var syntaxTree = CSharpSyntaxTree.ParseText(classContent);
            var root = syntaxTree.GetRoot();

            // Find the first class declaration (you can refine this if there are multiple classes)
            var classDeclaration = root.DescendantNodes().OfType<ClassDeclarationSyntax>().FirstOrDefault();

            // List to store extracted properties
            var properties = new List<CustomProperty>();

            if (classDeclaration != null)
            {
                // Look for property declarations inside the class
                var propertyDeclarations = classDeclaration.Members.OfType<PropertyDeclarationSyntax>();
                foreach (var property in propertyDeclarations)
                {
                    var propertyName = property.Identifier.Text; // Property name
                    var propertyType = property.Type.ToString(); // Property type

                    // Add the property and its type to the list
                    properties.Add(new CustomProperty
                    {
                        Name = propertyName,
                        Type = propertyType
                    });
                }
            }

            return properties;
        }
    }
}

public class CustomProperty // <- Renamed to avoid conflicts with System.Reflection.PropertyInfo
{
    public string Name { get; set; }
    public string Type { get; set; }
}
