/**
 * Ownership Analyzer
 *
 * Phase 2a: DAG (Directed Acyclic Graph) Analysis
 *
 * Validates ownership semantics:
 * 1. Detects cycles in share<T> relationships (prevents memory leaks)
 * 2. Validates ownership derivation rules (prevents logic errors)
 * 3. Ensures class fields have proper ownership annotations
 *
 * Rules:
 * - share<T> creates an ownership edge (A → B)
 * - Cycles in the ownership graph are forbidden
 * - own<T> → only use<T> derivation allowed
 * - share<T> → share<T> or use<T> allowed
 * - use<T> → only use<T> allowed
 */
import ts from 'typescript';
export class OwnershipAnalyzer {
    graph = {
        nodes: new Set(),
        edges: [],
        adjacencyList: new Map(),
    };
    diagnostics = [];
    /**
     * Analyze a source file for ownership relationships
     */
    analyze(sourceFile, checker) {
        this.collectTypeNodes(sourceFile);
        this.collectOwnershipEdges(sourceFile, checker);
    }
    /**
     * Finalize analysis after all files processed
     */
    finalize() {
        this.detectCycles();
        return this.diagnostics;
    }
    /**
     * Reset analyzer state
     */
    reset() {
        this.graph = {
            nodes: new Set(),
            edges: [],
            adjacencyList: new Map(),
        };
        this.diagnostics = [];
    }
    /**
     * Collect all type declarations (classes, interfaces)
     */
    collectTypeNodes(sourceFile) {
        const visit = (node) => {
            if (ts.isClassDeclaration(node) && node.name) {
                this.graph.nodes.add(node.name.text);
            }
            else if (ts.isInterfaceDeclaration(node)) {
                this.graph.nodes.add(node.name.text);
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
    }
    /**
     * Collect ownership edges from share<T> fields
     */
    collectOwnershipEdges(sourceFile, checker) {
        const visit = (node) => {
            if (ts.isPropertyDeclaration(node) || ts.isPropertySignature(node)) {
                this.analyzeProperty(node, sourceFile, checker);
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
    }
    /**
     * Analyze a property for share<T> ownership
     */
    analyzeProperty(node, sourceFile, _checker) {
        if (!node.type)
            return;
        const typeText = node.type.getText(sourceFile);
        const shareMatch = typeText.match(/share<(\w+)>/);
        if (shareMatch) {
            const ownedType = shareMatch[1];
            const ownerType = this.getContainingClass(node, sourceFile);
            if (ownerType && this.graph.nodes.has(ownedType)) {
                this.addEdge(ownerType, ownedType, node.name.getText(sourceFile), sourceFile, node);
            }
        }
        // TODO: Handle Array<share<T>>, Map<K, share<V>>, etc.
    }
    /**
     * Add an ownership edge to the graph
     */
    addEdge(from, to, via, sourceFile, node) {
        const edge = {
            from,
            to,
            via,
            location: this.getLocation(node, sourceFile),
        };
        this.graph.edges.push(edge);
        if (!this.graph.adjacencyList.has(from)) {
            this.graph.adjacencyList.set(from, []);
        }
        this.graph.adjacencyList.get(from).push(to);
    }
    /**
     * Detect cycles using DFS
     */
    detectCycles() {
        const visiting = new Set();
        const visited = new Set();
        const dfs = (node, path) => {
            if (visiting.has(node)) {
                // Found a cycle
                const cycleStart = path.indexOf(node);
                const cycle = [...path.slice(cycleStart), node];
                this.reportCycle(cycle);
                return true;
            }
            if (visited.has(node)) {
                return false;
            }
            visiting.add(node);
            path.push(node);
            const neighbors = this.graph.adjacencyList.get(node) || [];
            for (const neighbor of neighbors) {
                dfs(neighbor, path);
            }
            path.pop();
            visiting.delete(node);
            visited.add(node);
            return false;
        };
        for (const node of this.graph.nodes) {
            if (!visited.has(node)) {
                dfs(node, []);
            }
        }
    }
    /**
     * Report a detected cycle
     */
    reportCycle(cycle) {
        this.diagnostics.push({
            code: 'GS301',
            severity: 'error',
            message: `Ownership cycle detected: ${cycle.join(' → ')}. Use use<T> to break the cycle.`,
        });
    }
    /**
     * Get the containing class name
     */
    getContainingClass(node, _sourceFile) {
        let current = node.parent;
        while (current) {
            if (ts.isClassDeclaration(current) && current.name) {
                return current.name.text;
            }
            if (ts.isInterfaceDeclaration(current)) {
                return current.name.text;
            }
            current = current.parent;
        }
        return undefined;
    }
    /**
     * Get source location from node
     */
    getLocation(node, sourceFile) {
        const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
        return {
            fileName: sourceFile.fileName,
            line: line + 1,
            column: character + 1,
        };
    }
}
//# sourceMappingURL=ownership-analyzer.js.map