//! QVL Storage Layer - Stub Implementation
//! 
//! This is a stub/mock implementation for testing without libmdbx.
//! Replace with real libmdbx implementation when available.

const std = @import("std");
const types = @import("types.zig");

const NodeId = types.NodeId;
const RiskEdge = types.RiskEdge;
const RiskGraph = types.RiskGraph;

/// Mock persistent storage using in-memory HashMap
pub const PersistentGraph = struct {
    allocator: std.mem.Allocator,
    nodes: std.AutoHashMap(NodeId, void),
    edges: std.AutoHashMap(EdgeKey, RiskEdge),
    adjacency: std.AutoHashMap(NodeId, std.ArrayList(NodeId)),
    path: []const u8,
    
    const EdgeKey = struct {
        from: NodeId,
        to: NodeId,
        
        pub fn hash(self: EdgeKey) u64 {
            return @as(u64, self.from) << 32 | self.to;
        }
        
        pub fn eql(self: EdgeKey, other: EdgeKey) bool {
            return self.from == other.from and self.to == other.to;
        }
    };
    
    const Self = @This();
    
    /// Open or create persistent graph (mock: in-memory)
    pub fn open(path: []const u8, config: DBConfig, allocator: std.mem.Allocator) !Self {
        _ = config;
        return Self{
            .allocator = allocator,
            .nodes = std.AutoHashMap(NodeId, void).init(allocator),
            .edges = std.AutoHashMap(EdgeKey, RiskEdge).init(allocator),
            .adjacency = std.AutoHashMap(NodeId, std.ArrayList(NodeId)).init(allocator),
            .path = try allocator.dupe(u8, path),
        };
    }
    
    /// Close database
    pub fn close(self: *Self) void {
        // Clean up adjacency lists
        var it = self.adjacency.valueIterator();
        while (it.next()) |list| {
            list.deinit(self.allocator);
        }
        self.adjacency.deinit();
        self.edges.deinit();
        self.nodes.deinit();
        self.allocator.free(self.path);
    }
    
    /// Add node
    pub fn addNode(self: *Self, node: NodeId) !void {
        try self.nodes.put(node, {});
    }
    
    /// Add edge
    pub fn addEdge(self: *Self, edge: RiskEdge) !void {
        const key = EdgeKey{ .from = edge.from, .to = edge.to };
        try self.edges.put(key, edge);
        
        // Update adjacency
        const entry = try self.adjacency.getOrPut(edge.from);
        if (!entry.found_existing) {
            entry.value_ptr.* = .{}; // Empty ArrayList, allocator passed on append
        }
        try entry.value_ptr.append(self.allocator, edge.to);
    }
    
    /// Get outgoing neighbors
    pub fn getOutgoing(self: *Self, node: NodeId, allocator: std.mem.Allocator) ![]NodeId {
        if (self.adjacency.get(node)) |list| {
            // Copy to new slice with provided allocator
            return allocator.dupe(NodeId, list.items);
        }
        return allocator.dupe(NodeId, &[_]NodeId{});
    }
    
    /// Get specific edge
    pub fn getEdge(self: *Self, from: NodeId, to: NodeId) !?RiskEdge {
        const key = EdgeKey{ .from = from, .to = to };
        return self.edges.get(key);
    }
    
    /// Load in-memory RiskGraph
    pub fn toRiskGraph(self: *Self, allocator: std.mem.Allocator) !RiskGraph {
        var graph = RiskGraph.init(allocator);
        errdefer graph.deinit();
        
        var it = self.edges.valueIterator();
        while (it.next()) |edge| {
            try graph.addEdge(edge.*);
        }
        
        return graph;
    }
};

/// Database configuration (mock accepts same config for API compatibility)
pub const DBConfig = struct {
    max_readers: u32 = 64,
    max_dbs: u32 = 8,
    map_size: usize = 10 * 1024 * 1024,
    page_size: u32 = 4096,
};

// Re-export for integration.zig
pub const lmdb = struct {
    // Stub exports
};
