using Grpc.Core;
using GeViScopeBridge.Protos;
using GeViScopeBridge.SDK;
using GeViScopeBridge.Models;
using GeViScopeBridge.Services;
using Serilog;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

namespace GeViScopeBridge.Services
{
    /// <summary>
    /// gRPC service for GeViSoft configuration operations
    /// Provides read, parse, modify, and export capabilities for .set configuration files
    /// </summary>
    public class ConfigurationServiceImplementation : ConfigurationService.ConfigurationServiceBase
    {
        private readonly GeViSetupClientWrapper _setupClient;
        private readonly ILogger _logger;

        public ConfigurationServiceImplementation(
            GeViSetupClientWrapper setupClient,
            ILogger logger)
        {
            _setupClient = setupClient ?? throw new ArgumentNullException(nameof(setupClient));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// Read and parse complete configuration from GeViServer
        /// Returns all 19,903+ nodes with statistics
        /// </summary>
        public override async Task<ConfigurationResponse> ReadConfiguration(
            ReadConfigurationRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ReadConfiguration: Reading configuration from GeViServer");

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read and parse configuration
                var config = await Task.Run(() => _setupClient.ReadAndParseConfiguration());

                if (config == null)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                var response = new ConfigurationResponse
                {
                    Success = true,
                    FileSize = config.FileSize,
                    Header = config.Header,
                    Statistics = new ConfigurationStatistics
                    {
                        TotalNodes = config.Statistics?.TotalNodes ?? 0,
                        BooleanCount = config.Statistics?.BooleanCount ?? 0,
                        IntegerCount = config.Statistics?.IntegerCount ?? 0,
                        StringCount = config.Statistics?.StringCount ?? 0,
                        PropertyCount = config.Statistics?.PropertyCount ?? 0,
                        MarkerCount = config.Statistics?.MarkerCount ?? 0,
                        RulesSectionCount = config.Statistics?.RulesCount ?? 0
                    }
                };

                // Convert nodes to protobuf format (limit to first 1000 for performance)
                // For full node access, use ExportConfigurationJson
                foreach (Models.ConfigNode node in config.RootNodes.Take(1000))
                {
                    var protoNode = new Protos.ConfigNode
                    {
                        StartOffset = node.StartOffset,
                        EndOffset = node.EndOffset,
                        NodeType = node.NodeType,
                        Name = node.Name ?? "",
                        Value = node.Value?.ToString() ?? "",
                        ValueType = node.ValueType ?? ""
                    };

                    response.Nodes.Add(protoNode);
                }

                _logger.Information("ReadConfiguration: Successfully parsed {TotalNodes} nodes",
                    response.Statistics.TotalNodes);

                return response;
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ReadConfiguration failed");
                return new ConfigurationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to read configuration: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Export configuration as JSON
        /// Includes all nodes and statistics
        /// </summary>
        public override async Task<JsonExportResponse> ExportConfigurationJson(
            ExportJsonRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ExportConfigurationJson: Exporting configuration as JSON");

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read and parse configuration
                var config = await Task.Run(() => _setupClient.ReadAndParseConfiguration());

                if (config == null)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                // Serialize to JSON
                var options = new JsonSerializerOptions
                {
                    WriteIndented = true,
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                };

                string json = JsonSerializer.Serialize(config, options);

                _logger.Information("ExportConfigurationJson: Exported {Size} bytes of JSON ({Nodes} nodes)",
                    json.Length, config.Statistics?.TotalNodes ?? 0);

                return new JsonExportResponse
                {
                    Success = true,
                    JsonData = json,
                    JsonSize = json.Length
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ExportConfigurationJson failed");
                return new JsonExportResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to export configuration: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Modify configuration values and write back to server
        /// Preserves binary structure (in-place modification)
        /// </summary>
        public override async Task<ModifyConfigurationResponse> ModifyConfiguration(
            ModifyConfigurationRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ModifyConfiguration: Applying {Count} modifications",
                    request.Modifications.Count);

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read and parse current configuration
                var config = await Task.Run(() => _setupClient.ReadAndParseConfiguration());

                if (config == null)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                // Apply modifications
                int modificationsApplied = 0;
                var modifier = new InPlaceConfigModifier();
                byte[] modifiedData = config.GetDataForWriting();

                foreach (var mod in request.Modifications)
                {
                    // Find node by offset
                    var node = config.RootNodes.FirstOrDefault(n => n.StartOffset == mod.StartOffset);
                    if (node == null)
                    {
                        _logger.Warning("ModifyConfiguration: Node not found at offset {Offset}", mod.StartOffset);
                        continue;
                    }

                    // Verify node type matches
                    if (node.NodeType != mod.NodeType)
                    {
                        _logger.Warning("ModifyConfiguration: Node type mismatch at offset {Offset}: expected {Expected}, got {Got}",
                            mod.StartOffset, node.NodeType, mod.NodeType);
                        continue;
                    }

                    // Parse value based on type
                    object newValue;
                    switch (mod.NodeType)
                    {
                        case "boolean":
                            newValue = bool.Parse(mod.NewValue);
                            break;
                        case "integer":
                            newValue = int.Parse(mod.NewValue);
                            break;
                        case "string":
                            newValue = mod.NewValue;
                            break;
                        default:
                            _logger.Warning("ModifyConfiguration: Unsupported node type {Type} at offset {Offset}",
                                mod.NodeType, mod.StartOffset);
                            continue;
                    }

                    // Apply modification
                    bool success = modifier.ModifyNode(modifiedData, node, newValue);
                    if (success)
                    {
                        modificationsApplied++;
                        _logger.Debug("ModifyConfiguration: Modified {Type} at offset {Offset}: {OldValue} → {NewValue}",
                            node.NodeType, node.StartOffset, node.Value, newValue);
                    }
                    else
                    {
                        _logger.Warning("ModifyConfiguration: Failed to modify node at offset {Offset}", mod.StartOffset);
                    }
                }

                // Write modified configuration back to server
                bool writeSuccess = await _setupClient.WriteSetupAsync(modifiedData);

                if (!writeSuccess)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to write modified configuration to GeViServer"));
                }

                _logger.Information("ModifyConfiguration: Successfully applied {Count} modifications",
                    modificationsApplied);

                return new ModifyConfigurationResponse
                {
                    Success = true,
                    ModificationsApplied = modificationsApplied
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ModifyConfiguration failed");
                return new ModifyConfigurationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to modify configuration: {ex.Message}",
                    ModificationsApplied = 0
                };
            }
        }

        /// <summary>
        /// Import complete configuration from JSON and write to GeViServer
        /// Allows adding new action mappings and modifying entire configuration
        /// </summary>
        public override async Task<ImportConfigurationResponse> ImportConfiguration(
            ImportConfigurationRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ImportConfiguration: Importing configuration from JSON ({Size} bytes)",
                    request.JsonData.Length);

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Deserialize JSON to ComprehensiveConfigFile
                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                };

                ComprehensiveConfigFile? config;
                try
                {
                    config = JsonSerializer.Deserialize<ComprehensiveConfigFile>(request.JsonData, options);
                }
                catch (JsonException jsonEx)
                {
                    _logger.Error(jsonEx, "ImportConfiguration: Invalid JSON format");
                    return new ImportConfigurationResponse
                    {
                        Success = false,
                        ErrorMessage = $"Invalid JSON format: {jsonEx.Message}"
                    };
                }

                if (config == null)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.InvalidArgument, "Failed to deserialize configuration JSON"));
                }

                _logger.Information("ImportConfiguration: Deserialized {NodeCount} nodes",
                    config.RootNodes.Count);

                // Convert JSON to binary .set format
                var writer = new ConfigurationWriter(_logger);
                byte[] binaryData;

                try
                {
                    binaryData = await Task.Run(() => writer.WriteToBinary(config));
                }
                catch (Exception writerEx)
                {
                    _logger.Error(writerEx, "ImportConfiguration: Failed to convert JSON to binary format");
                    return new ImportConfigurationResponse
                    {
                        Success = false,
                        ErrorMessage = $"Failed to convert to binary format: {writerEx.Message}"
                    };
                }

                _logger.Information("ImportConfiguration: Converted to {Size} bytes binary data",
                    binaryData.Length);

                // Write to GeViServer via SetupClient
                bool writeSuccess = await _setupClient.WriteSetupAsync(binaryData);

                if (!writeSuccess)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("ImportConfiguration: Successfully wrote {Size} bytes ({NodeCount} nodes) to GeViServer",
                    binaryData.Length, config.RootNodes.Count);

                return new ImportConfigurationResponse
                {
                    Success = true,
                    BytesWritten = binaryData.Length,
                    NodesImported = config.RootNodes.Count
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ImportConfiguration failed");
                return new ImportConfigurationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to import configuration: {ex.Message}",
                    BytesWritten = 0,
                    NodesImported = 0
                };
            }
        }

        /// <summary>
        /// Read ONLY action mappings (Rules markers) using selective parser
        /// Much faster than full configuration read - only scans for Rules markers
        /// </summary>
        public override async Task<ActionMappingsResponse> ReadActionMappings(
            ReadActionMappingsRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ReadActionMappings: Reading action mappings from GeViServer");

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read raw configuration data
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                // USE FOLDER TREE PARSER
                _logger.Information("Using FolderTreeParser to parse configuration");
                var treeParser = new FolderTreeParser(_logger);
                var root = treeParser.Parse(configData);

                // Navigate to MappingRules folder
                var mappingRules = root.Navigate("MappingRules");
                if (mappingRules == null || mappingRules.Type != "folder")
                {
                    _logger.Warning("MappingRules folder not found in configuration");
                    return new ActionMappingsResponse
                    {
                        Success = true,
                        TotalCount = 0
                    };
                }

                int mappingCount = mappingRules.Children?.Count(c => c.Type == "folder") ?? 0;
                _logger.Information("FolderTreeParser found {Count} action mappings", mappingCount);

                var response = new ActionMappingsResponse
                {
                    Success = true,
                    TotalCount = mappingCount
                };

                // Convert each rule folder to protobuf format
                if (mappingRules.Children != null)
                {
                    foreach (var ruleFolder in mappingRules.Children.Where(c => c.Type == "folder"))
                    {
                        // Extract mapping name from @ field
                        var nameNode = ruleFolder.FindChild("@");
                        string mappingName = nameNode?.StringValue ?? $"Mapping {ruleFolder.Name}";

                        var mapping = new ConfigActionMapping
                        {
                            Name = mappingName,
                            StartOffset = 0,  // Folder tree doesn't track offsets
                            EndOffset = 0
                        };

                        // Find Rules folder containing output actions
                        var rulesFolder = ruleFolder.FindChild("Rules");
                        if (rulesFolder != null && rulesFolder.Children != null)
                        {
                            foreach (var outputFolder in rulesFolder.Children.Where(c => c.Type == "folder"))
                            {
                                // Extract action definition
                                var outputNameNode = outputFolder.FindChild("@");
                                var gscActionNode = outputFolder.FindChild("GscAction");
                                var gcoreActionNode = outputFolder.FindChild("GCoreAction");

                                string actionName = gscActionNode?.StringValue ?? gcoreActionNode?.StringValue ?? outputNameNode?.StringValue ?? "";

                                if (!string.IsNullOrEmpty(actionName))
                                {
                                    var actionDef = new Protos.ActionDefinition
                                    {
                                        Action = actionName
                                    };

                                    // Extract parameters (all children except @, @!, @@, GscAction, GCoreAction, GscServer, GCoreServer)
                                    if (outputFolder.Children != null)
                                    {
                                        foreach (var paramNode in outputFolder.Children)
                                        {
                                            if (paramNode.Name != "@" && paramNode.Name != "@!" && paramNode.Name != "@@" &&
                                                paramNode.Name != "GscAction" && paramNode.Name != "GCoreAction" &&
                                                paramNode.Name != "GscServer" && paramNode.Name != "GCoreServer")
                                            {
                                                actionDef.Parameters.Add(new Protos.ActionParameter
                                                {
                                                    Name = paramNode.Name,
                                                    Value = paramNode.StringValue ?? paramNode.IntValue?.ToString() ?? ""
                                                });
                                            }
                                        }
                                    }

                                    mapping.OutputActions.Add(actionDef);
                                }
                            }
                        }

                        response.Mappings.Add(mapping);
                    }
                }

                _logger.Information("ReadActionMappings: Returning {Count} action mappings",
                    response.TotalCount);

                return response;
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ReadActionMappings failed");
                return new ActionMappingsResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to read action mappings: {ex.Message}",
                    TotalCount = 0
                };
            }
        }

        /// <summary>
        /// Read specific markers by name using selective parser
        /// Extensible method for reading any configuration type
        /// </summary>
        public override async Task<SelectiveConfigResponse> ReadSpecificMarkers(
            ReadSpecificMarkersRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ReadSpecificMarkers: Reading markers: {Markers}",
                    string.Join(", ", request.MarkerNames));

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read raw configuration data
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(
                        new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                // Use selective parser
                var parser = new SelectiveConfigParser();
                var result = parser.ParseMarkers(configData, request.MarkerNames.ToArray());

                var response = new SelectiveConfigResponse
                {
                    Success = true,
                    FileSize = result.FileSize,
                    MarkersFound = result.MarkersFound
                };

                response.RequestedMarkers.AddRange(result.RequestedMarkers);

                // Convert nodes to protobuf format
                foreach (var node in result.ExtractedNodes)
                {
                    var protoNode = new Protos.ConfigNode
                    {
                        StartOffset = node.StartOffset,
                        EndOffset = node.EndOffset,
                        NodeType = node.NodeType,
                        Name = node.Name ?? "",
                        Value = SerializeNodeValue(node.Value),
                        ValueType = node.ValueType ?? ""
                    };

                    response.ExtractedNodes.Add(protoNode);
                }

                _logger.Information("ReadSpecificMarkers: Found {Count} markers",
                    response.MarkersFound);

                return response;
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ReadSpecificMarkers failed");
                return new SelectiveConfigResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to read specific markers: {ex.Message}",
                    FileSize = 0,
                    MarkersFound = 0
                };
            }
        }

        /// <summary>
        /// Create a new action mapping
        /// </summary>
        public override async Task<ActionMappingOperationResponse> CreateActionMapping(
            CreateActionMappingRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("CreateActionMapping: Creating new action mapping");

                // Validate request
                if (request.Mapping == null)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Mapping data is required"));
                }

                if (request.Mapping.OutputActions == null || request.Mapping.OutputActions.Count == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "At least one output action is required"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("CreateActionMapping: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree (correct format!)
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Convert protobuf actions to OutputAction list
                var outputActions = new List<OutputAction>();
                foreach (var action in request.Mapping.OutputActions)
                {
                    var outputAction = new OutputAction
                    {
                        Name = action.Action,  // Action name as display name
                        Action = action.Action,
                        Server = ""  // Can be extended later
                    };

                    foreach (var param in action.Parameters)
                    {
                        outputAction.Parameters[param.Name] = param.Value;
                    }

                    outputActions.Add(outputAction);
                }

                // Add the new mapping to the folder tree
                var mappingManager = new ActionMappingManager(_logger);
                int? videoInput = request.Mapping.VideoInput != 0 ? request.Mapping.VideoInput : (int?)null;
                mappingManager.AddActionMapping(root, request.Mapping.Name ?? "New Mapping", outputActions, videoInput);

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("CreateActionMapping: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("CreateActionMapping: Successfully created new mapping '{Name}'", request.Mapping.Name);

                // Return the created mapping
                var createdMapping = new ConfigActionMapping
                {
                    Name = request.Mapping.Name ?? "",
                    StartOffset = configData.Length, // Appended at end
                    EndOffset = updatedConfig.Length
                };

                // Add actions
                foreach (var action in request.Mapping.OutputActions)
                {
                    createdMapping.OutputActions.Add(action);
                }

                return new ActionMappingOperationResponse
                {
                    Success = true,
                    Message = "Action mapping created successfully",
                    Mapping = createdMapping
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "CreateActionMapping failed");
                return new ActionMappingOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to create action mapping: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Update an existing action mapping by ID
        /// </summary>
        public override async Task<ActionMappingOperationResponse> UpdateActionMapping(
            UpdateActionMappingRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("UpdateActionMapping: Updating mapping ID {MappingId}", request.MappingId);

                // Validate request
                if (request.MappingId < 1)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Mapping ID must be >= 1"));
                }

                if (request.Mapping == null)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Mapping data is required"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("UpdateActionMapping: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Navigate to MappingRules folder
                var mappingRules = root.Navigate("MappingRules");
                if (mappingRules == null || mappingRules.Type != "folder")
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "MappingRules folder not found in configuration"));
                }

                // Find the rule by ID (request.MappingId is 1-based)
                var allRules = mappingRules.Children?.Where(c => c.Type == "folder").ToList() ?? new List<FolderNode>();

                if (request.MappingId > allRules.Count)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound,
                        $"Mapping ID {request.MappingId} not found (only {allRules.Count} mappings exist)"));
                }

                var ruleToUpdate = allRules[request.MappingId - 1];
                _logger.Information("UpdateActionMapping: Found rule with folder name '{Name}'", ruleToUpdate.Name);

                // Update the rule's fields
                if (ruleToUpdate.Children == null)
                {
                    ruleToUpdate.Children = new List<FolderNode>();
                }

                // Update caption if provided
                if (!string.IsNullOrEmpty(request.Mapping.Name))
                {
                    var captionNode = ruleToUpdate.Children.FirstOrDefault(c => c.Name == "@");
                    if (captionNode != null)
                    {
                        captionNode.StringValue = request.Mapping.Name;
                        _logger.Information("UpdateActionMapping: Updated caption to '{Caption}'", request.Mapping.Name);
                    }
                }

                // Update VideoInput if provided
                if (request.Mapping.VideoInput != 0)
                {
                    var videoInputNode = ruleToUpdate.Children.FirstOrDefault(c => c.Name == "VideoInput");
                    if (videoInputNode != null)
                    {
                        videoInputNode.IntValue = request.Mapping.VideoInput;
                        _logger.Information("UpdateActionMapping: Updated VideoInput to {VideoInput}", request.Mapping.VideoInput);
                    }
                }

                // Update output actions if provided
                if (request.Mapping.OutputActions != null && request.Mapping.OutputActions.Count > 0)
                {
                    var rulesFolder = ruleToUpdate.Children.FirstOrDefault(c => c.Name == "Rules" && c.Type == "folder");
                    if (rulesFolder != null)
                    {
                        // Clear existing output actions
                        rulesFolder.Children = new List<FolderNode>();

                        // Add new output actions
                        var outputActions = new List<OutputAction>();
                        foreach (var action in request.Mapping.OutputActions)
                        {
                            outputActions.Add(new OutputAction
                            {
                                Name = action.Action,
                                Action = action.Action,
                                Server = ""
                            });
                        }

                        var mappingManager = new ActionMappingManager(_logger);
                        int outputId = 0;
                        foreach (var action in outputActions)
                        {
                            var outputFolder = mappingManager.CreateOutputFolder(outputId.ToString(), action);
                            rulesFolder.Children.Add(outputFolder);
                            outputId++;
                        }

                        _logger.Information("UpdateActionMapping: Updated {Count} output actions", outputActions.Count);
                    }
                }

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("UpdateActionMapping: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("UpdateActionMapping: Successfully updated mapping ID {MappingId}", request.MappingId);

                // Return the updated mapping
                var updatedMapping = new ConfigActionMapping
                {
                    Name = request.Mapping.Name ?? ""
                };

                foreach (var action in request.Mapping.OutputActions)
                {
                    updatedMapping.OutputActions.Add(action);
                }

                return new ActionMappingOperationResponse
                {
                    Success = true,
                    Message = $"Action mapping {request.MappingId} updated successfully",
                    Mapping = updatedMapping
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "UpdateActionMapping failed");
                return new ActionMappingOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to update action mapping: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Delete an action mapping by ID
        /// </summary>
        public override async Task<ActionMappingOperationResponse> DeleteActionMapping(
            DeleteActionMappingRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("DeleteActionMapping: Deleting mapping ID {MappingId}", request.MappingId);

                // Validate request
                if (request.MappingId < 1)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Mapping ID must be >= 1"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("DeleteActionMapping: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Navigate to MappingRules folder
                var mappingRules = root.Navigate("MappingRules");
                if (mappingRules == null || mappingRules.Type != "folder")
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "MappingRules folder not found in configuration"));
                }

                // Find the rule by ID (request.MappingId is 1-based)
                var allRules = mappingRules.Children?.Where(c => c.Type == "folder").ToList() ?? new List<FolderNode>();

                if (request.MappingId > allRules.Count)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound,
                        $"Mapping ID {request.MappingId} not found (only {allRules.Count} mappings exist)"));
                }

                var ruleToDelete = allRules[request.MappingId - 1];
                _logger.Information("DeleteActionMapping: Found rule with folder name '{Name}'", ruleToDelete.Name);

                // Get the caption for the response
                var captionNode = ruleToDelete.Children?.FirstOrDefault(c => c.Name == "@");
                string deletedName = captionNode?.StringValue ?? $"Mapping {request.MappingId}";

                // Remove the rule from MappingRules
                mappingRules.Children.Remove(ruleToDelete);

                _logger.Information("DeleteActionMapping: Removed mapping '{Name}' from folder tree", deletedName);

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("DeleteActionMapping: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("DeleteActionMapping: Successfully deleted mapping ID {MappingId} ('{Name}')", request.MappingId, deletedName);

                return new ActionMappingOperationResponse
                {
                    Success = true,
                    Message = $"Action mapping {request.MappingId} ('{deletedName}') deleted successfully",
                    Mapping = null
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "DeleteActionMapping failed");
                return new ActionMappingOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to delete action mapping: {ex.Message}"
                };
            }
        }

        // ========== SERVER CRUD OPERATIONS ==========

        /// <summary>
        /// Create a new G-core server
        /// </summary>
        public override async Task<ServerOperationResponse> CreateServer(
            CreateServerRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("CreateServer: Creating new server '{ServerId}'", request.Server.Id);

                // Validate request
                if (request.Server == null || string.IsNullOrEmpty(request.Server.Id))
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Server ID is required"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("CreateServer: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Navigate to GeViGCoreServer folder
                var gCoreServerFolder = root.Navigate("GeViGCoreServer");
                if (gCoreServerFolder == null || gCoreServerFolder.Type != "folder")
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "GeViGCoreServer folder not found in configuration"));
                }

                // Check if server already exists
                if (gCoreServerFolder.Children != null &&
                    gCoreServerFolder.Children.Any(c => c.Type == "folder" && c.Name == request.Server.Id))
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.AlreadyExists,
                        $"Server '{request.Server.Id}' already exists"));
                }

                // Create new server folder
                // Field order matches working Python implementation: Alias, DeactivateEcho, DeactivateLiveCheck, Enabled, Host, Password, User
                var newServer = new FolderNode
                {
                    Type = "folder",
                    Name = request.Server.Id,
                    Children = new List<FolderNode>
                    {
                        new FolderNode { Type = "string", Name = "Alias", StringValue = request.Server.Alias ?? "" },
                        new FolderNode { Type = "bool", Name = "DeactivateEcho", BoolValue = request.Server.DeactivateEcho },
                        new FolderNode { Type = "bool", Name = "DeactivateLiveCheck", BoolValue = request.Server.DeactivateLiveCheck },
                        new FolderNode { Type = "bool", Name = "Enabled", BoolValue = request.Server.Enabled },
                        new FolderNode { Type = "string", Name = "Host", StringValue = request.Server.Host ?? "" },
                        new FolderNode { Type = "string", Name = "Password", StringValue = request.Server.Password ?? "" },
                        new FolderNode { Type = "string", Name = "User", StringValue = request.Server.User ?? "" }
                    }
                };

                // Add server to GeViGCoreServer folder
                if (gCoreServerFolder.Children == null)
                {
                    gCoreServerFolder.Children = new List<FolderNode>();
                }
                gCoreServerFolder.Children.Add(newServer);

                _logger.Information("CreateServer: Added server folder '{ServerId}' to GeViGCoreServer", request.Server.Id);

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("CreateServer: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("CreateServer: Successfully created server '{ServerId}'", request.Server.Id);

                return new ServerOperationResponse
                {
                    Success = true,
                    Message = $"Server '{request.Server.Id}' created successfully",
                    Server = request.Server,
                    BytesWritten = updatedConfig.Length
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "CreateServer failed");
                return new ServerOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to create server: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Update an existing G-core server
        /// </summary>
        public override async Task<ServerOperationResponse> UpdateServer(
            UpdateServerRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("UpdateServer: Updating server '{ServerId}'", request.ServerId);

                // Validate request
                if (string.IsNullOrEmpty(request.ServerId))
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Server ID is required"));
                }

                if (request.Server == null)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Server data is required"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("UpdateServer: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Navigate to GeViGCoreServer folder
                var gCoreServerFolder = root.Navigate("GeViGCoreServer");
                if (gCoreServerFolder == null || gCoreServerFolder.Type != "folder")
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "GeViGCoreServer folder not found in configuration"));
                }

                // Find the server
                var serverToUpdate = gCoreServerFolder.Children?
                    .FirstOrDefault(c => c.Type == "folder" && c.Name == request.ServerId);

                if (serverToUpdate == null)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound,
                        $"Server '{request.ServerId}' not found"));
                }

                _logger.Information("UpdateServer: Found server folder '{ServerId}'", request.ServerId);

                // Update server properties
                if (serverToUpdate.Children == null)
                {
                    serverToUpdate.Children = new List<FolderNode>();
                }

                UpdateOrAddChild(serverToUpdate, "Alias", "string", request.Server.Alias);
                UpdateOrAddChild(serverToUpdate, "DeactivateEcho", "bool", request.Server.DeactivateEcho);
                UpdateOrAddChild(serverToUpdate, "DeactivateLiveCheck", "bool", request.Server.DeactivateLiveCheck);
                UpdateOrAddChild(serverToUpdate, "Enabled", "bool", request.Server.Enabled);
                UpdateOrAddChild(serverToUpdate, "Host", "string", request.Server.Host);
                UpdateOrAddChild(serverToUpdate, "Password", "string", request.Server.Password);
                UpdateOrAddChild(serverToUpdate, "User", "string", request.Server.User);

                _logger.Information("UpdateServer: Updated server properties for '{ServerId}'", request.ServerId);

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("UpdateServer: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("UpdateServer: Successfully updated server '{ServerId}'", request.ServerId);

                return new ServerOperationResponse
                {
                    Success = true,
                    Message = $"Server '{request.ServerId}' updated successfully",
                    Server = request.Server,
                    BytesWritten = updatedConfig.Length
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "UpdateServer failed");
                return new ServerOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to update server: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Delete a G-core server
        /// </summary>
        public override async Task<ServerOperationResponse> DeleteServer(
            DeleteServerRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("DeleteServer: Deleting server '{ServerId}'", request.ServerId);

                // Validate request
                if (string.IsNullOrEmpty(request.ServerId))
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Server ID is required"));
                }

                // Check connection
                if (!_setupClient.IsConnected)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.FailedPrecondition, "SetupClient is not connected to GeViServer"));
                }

                // Read current configuration
                byte[] configData = await _setupClient.ReadSetupAsync();
                if (configData == null || configData.Length == 0)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to read configuration from GeViServer"));
                }

                _logger.Information("DeleteServer: Original config size: {Size} bytes", configData.Length);

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Navigate to GeViGCoreServer folder
                var gCoreServerFolder = root.Navigate("GeViGCoreServer");
                if (gCoreServerFolder == null || gCoreServerFolder.Type != "folder")
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "GeViGCoreServer folder not found in configuration"));
                }

                // Find and remove the server
                var serverToDelete = gCoreServerFolder.Children?
                    .FirstOrDefault(c => c.Type == "folder" && c.Name == request.ServerId);

                if (serverToDelete == null)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound,
                        $"Server '{request.ServerId}' not found"));
                }

                gCoreServerFolder.Children.Remove(serverToDelete);
                _logger.Information("DeleteServer: Removed server folder '{ServerId}' from GeViGCoreServer", request.ServerId);

                // Serialize back to binary
                var writer = new FolderTreeWriter(_logger);
                byte[] updatedConfig = writer.Write(root);

                _logger.Information("DeleteServer: Modified config size: {Size} bytes (change: {Delta} bytes)",
                    updatedConfig.Length, (int)updatedConfig.Length - configData.Length);

                // Write back to GeViServer
                bool writeSuccess = await _setupClient.WriteSetupAsync(updatedConfig);
                if (!writeSuccess)
                {
                    throw new RpcException(new Grpc.Core.Status(StatusCode.Internal, "Failed to write configuration to GeViServer"));
                }

                _logger.Information("DeleteServer: Successfully deleted server '{ServerId}'", request.ServerId);

                return new ServerOperationResponse
                {
                    Success = true,
                    Message = $"Server '{request.ServerId}' deleted successfully",
                    BytesWritten = updatedConfig.Length
                };
            }
            catch (RpcException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "DeleteServer failed");
                return new ServerOperationResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to delete server: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Helper method to update or add a child node
        /// </summary>
        private void UpdateOrAddChild(FolderNode parent, string name, string type, object value)
        {
            var child = parent.Children?.FirstOrDefault(c => c.Name == name);

            if (child != null)
            {
                // Update existing node
                if (type == "string")
                {
                    child.StringValue = value?.ToString() ?? "";
                }
                else if (type == "bool")
                {
                    child.BoolValue = Convert.ToBoolean(value);
                }
                else if (type == "int32" || type == "int16" || type == "byte")
                {
                    child.IntValue = Convert.ToInt32(value);
                }
            }
            else
            {
                // Add new node
                var newChild = new FolderNode
                {
                    Type = type,
                    Name = name
                };

                if (type == "string")
                {
                    newChild.StringValue = value?.ToString() ?? "";
                }
                else if (type == "bool")
                {
                    newChild.BoolValue = Convert.ToBoolean(value);
                }
                else if (type == "int32" || type == "int16" || type == "byte")
                {
                    newChild.IntValue = Convert.ToInt32(value);
                }

                parent.Children.Add(newChild);
            }
        }

        /// <summary>
        /// Create a ConfigNode for an action mapping from protobuf data
        /// </summary>
        private Models.ConfigNode CreateActionMappingNode(ActionMappingInput mapping)
        {
            var node = new Models.ConfigNode
            {
                NodeType = "marker",
                Name = "ules",
                Children = new List<Models.ConfigNode>()
            };

            // Add action nodes
            foreach (var actionDef in mapping.OutputActions)
            {
                var actionNode = new Models.ConfigNode
                {
                    NodeType = "action",
                    Name = actionDef.Action,
                    Value = actionDef.Action,
                    Children = new List<Models.ConfigNode>()
                };

                // Add action parameters
                foreach (var param in actionDef.Parameters)
                {
                    actionNode.Children.Add(new Models.ConfigNode
                    {
                        NodeType = "property",
                        Name = param.Name,
                        Value = param.Value,
                        ValueType = "string"
                    });
                }

                node.Children.Add(actionNode);
            }

            return node;
        }

        /// <summary>
        /// Update a mapping node with new data
        /// </summary>
        private void UpdateMappingNode(Models.ConfigNode node, ActionMappingInput newData)
        {
            // Update name if provided
            if (!string.IsNullOrEmpty(newData.Name))
            {
                node.Name = newData.Name;
            }

            // Clear existing action nodes
            node.Children.RemoveAll(c => c.NodeType == "action");

            // Add new actions
            foreach (var actionDef in newData.OutputActions)
            {
                var actionNode = new Models.ConfigNode
                {
                    NodeType = "action",
                    Name = actionDef.Action,
                    Value = actionDef.Action,
                    Children = new List<Models.ConfigNode>()
                };

                // Add action parameters
                foreach (var param in actionDef.Parameters)
                {
                    actionNode.Children.Add(new Models.ConfigNode
                    {
                        NodeType = "property",
                        Name = param.Name,
                        Value = param.Value,
                        ValueType = "string"
                    });
                }

                node.Children.Add(actionNode);
            }
        }

        private string SerializeNodeValue(object? value)
        {
            if (value == null) return "";
            if (value is string str) return str;
            if (value is System.Collections.Generic.List<string> list)
                return JsonSerializer.Serialize(list);
            return value.ToString() ?? "";
        }

        // TREE FORMAT METHOD

        /// <summary>
        /// Read configuration as hierarchical folder tree (RECOMMENDED FORMAT)
        /// Much more readable than flat offset-based format
        /// </summary>
        public override async Task<ConfigurationTreeResponse> ReadConfigurationTree(
            ReadConfigurationTreeRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ReadConfigurationTree: Reading configuration as folder tree");

                // Read binary configuration
                byte[] configData = await _setupClient.ReadSetupAsync();

                // Parse as folder tree
                var parser = new FolderTreeParser(_logger);
                var root = parser.Parse(configData);

                // Convert to protobuf TreeNode
                var protoRoot = ConvertToProtoTreeNode(root);

                // Count total nodes (recursive)
                int totalNodes = CountNodes(root);

                _logger.Information("ReadConfigurationTree: Successfully parsed tree with {NodeCount} nodes", totalNodes);

                return new ConfigurationTreeResponse
                {
                    Success = true,
                    Root = protoRoot,
                    TotalNodes = totalNodes
                };
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ReadConfigurationTree failed");
                return new ConfigurationTreeResponse
                {
                    Success = false,
                    ErrorMessage = $"Failed to read configuration tree: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Convert FolderNode to protobuf TreeNode
        /// </summary>
        private TreeNode ConvertToProtoTreeNode(FolderNode node)
        {
            var protoNode = new TreeNode
            {
                Type = node.Type,
                Name = node.Name
            };

            // Set value based on type
            if (node.Type == "string")
            {
                protoNode.StringValue = node.StringValue ?? "";
            }
            else if (node.Type == "bool" || node.Type == "byte" ||
                     node.Type == "int16" || node.Type == "int32" || node.Type == "int64")
            {
                protoNode.IntValue = node.IntValue ?? 0;
            }

            // Add children recursively
            if (node.Type == "folder" && node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    protoNode.Children.Add(ConvertToProtoTreeNode(child));
                }
            }

            return protoNode;
        }

        /// <summary>
        /// Count total nodes in tree (recursive)
        /// </summary>
        private int CountNodes(FolderNode node)
        {
            int count = 1; // Count this node

            if (node.Type == "folder" && node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    count += CountNodes(child);
                }
            }

            return count;
        }

        // REGISTRY EXPLORATION METHODS (Not implemented - folder tree approach used instead)

        public override async Task<RegistryNodesResponse> ListRegistryNodes(
            ListRegistryNodesRequest request,
            ServerCallContext context)
        {
            return await Task.FromResult(new RegistryNodesResponse
            {
                Success = false,
                ErrorMessage = "Registry exploration not implemented - using folder tree approach"
            });
        }

        public override async Task<RegistryNodeDetailsResponse> GetRegistryNodeDetails(
            GetRegistryNodeDetailsRequest request,
            ServerCallContext context)
        {
            return await Task.FromResult(new RegistryNodeDetailsResponse
            {
                Success = false,
                ErrorMessage = "Registry exploration not implemented - using folder tree approach"
            });
        }

        public override async Task<ActionMappingPathsResponse> SearchActionMappingPaths(
            SearchActionMappingPathsRequest request,
            ServerCallContext context)
        {
            return await Task.FromResult(new ActionMappingPathsResponse
            {
                Success = false,
                ErrorMessage = "Registry exploration not implemented - using folder tree approach"
            });
        }
    }
}
