/**
 * @module chevrotain-parser/connect-parser
 *
 * Parser for @connect declarations using Chevrotain.
 */
import { CstParser } from 'chevrotain';
import { JSDocLexer, ConnectTag, Identifier, Arrow, Dot, Colon, AsKeyword, allTokens } from './tokens.js';
// =============================================================================
// Parser Definition
// =============================================================================
class ConnectParser extends CstParser {
    constructor() {
        super(allTokens);
        this.performSelfAnalysis();
    }
    // Entry rule for connect line: @connect A.port -> B.port [as type]
    connectLine = this.RULE('connectLine', () => {
        this.CONSUME(ConnectTag);
        this.SUBRULE(this.portRef, { LABEL: 'sourceRef' });
        this.CONSUME(Arrow);
        this.SUBRULE2(this.portRef, { LABEL: 'targetRef' });
        this.OPTION(() => {
            this.CONSUME(AsKeyword);
            this.CONSUME(Identifier, { LABEL: 'coerceType' });
        });
    });
    // node.port, node.port:scope, or pseudo-node (secret:NAME)
    portRef = this.RULE('portRef', () => {
        this.CONSUME(Identifier, { LABEL: 'nodeId' });
        this.OR([
            {
                ALT: () => {
                    this.CONSUME(Dot);
                    this.CONSUME2(Identifier, { LABEL: 'portName' });
                    this.OPTION(() => {
                        this.CONSUME(Colon);
                        this.CONSUME3(Identifier, { LABEL: 'scopeName' });
                    });
                },
            },
            {
                // pseudo-node: secret:NAME (nodeId="secret", colon, pseudoName="NAME")
                ALT: () => {
                    this.CONSUME2(Colon, { LABEL: 'pseudoColon' });
                    this.CONSUME4(Identifier, { LABEL: 'pseudoName' });
                },
            },
        ]);
    });
}
// =============================================================================
// Parser Instance (singleton)
// =============================================================================
const parserInstance = new ConnectParser();
// =============================================================================
// CST Visitor
// =============================================================================
const BaseVisitor = parserInstance.getBaseCstVisitorConstructor();
class ConnectVisitor extends BaseVisitor {
    constructor() {
        super();
        this.validateVisitor();
    }
    connectLine(ctx) {
        const source = this.visit(ctx.sourceRef);
        const target = this.visit(ctx.targetRef);
        const result = { source, target };
        if (ctx.coerceType?.[0]) {
            const validTypes = new Set(['string', 'number', 'boolean', 'json', 'object']);
            const raw = ctx.coerceType[0].image;
            if (validTypes.has(raw)) {
                result.coerce = raw;
            }
            else {
                result.invalidCoerceType = raw;
            }
        }
        return result;
    }
    portRef(ctx) {
        const nodeId = ctx.nodeId[0].image;
        // Pseudo-node branch: secret:NAME -> { nodeId: "secret:NAME", portName: "value" }
        if (ctx.pseudoColon) {
            const pseudoName = ctx.pseudoName[0].image;
            return { nodeId: `${nodeId}:${pseudoName}`, portName: 'value' };
        }
        const portName = ctx.portName[0].image;
        const scope = ctx.scopeName?.[0]?.image;
        return { nodeId, portName, scope };
    }
}
const visitorInstance = new ConnectVisitor();
// =============================================================================
// Public API
// =============================================================================
/**
 * Parse a @connect line and return structured result.
 * Returns null if the line is not a connect declaration.
 */
export function parseConnectLine(input, warnings) {
    const lexResult = JSDocLexer.tokenize(input);
    if (lexResult.errors.length > 0) {
        return null;
    }
    // Check if starts with @connect
    if (lexResult.tokens.length === 0) {
        return null;
    }
    const firstToken = lexResult.tokens[0];
    if (firstToken.tokenType !== ConnectTag) {
        return null;
    }
    parserInstance.input = lexResult.tokens;
    const cst = parserInstance.connectLine();
    if (parserInstance.errors.length > 0) {
        const firstError = parserInstance.errors[0];
        const truncatedInput = input.length > 60 ? input.substring(0, 60) + '...' : input;
        warnings.push(`Failed to parse connect line: "${truncatedInput}"\n` +
            `  Error: ${firstError.message}\n` +
            `  Expected format: @connect sourceNode.port -> targetNode.port`);
        return null;
    }
    const result = visitorInstance.visit(cst);
    if (result.invalidCoerceType) {
        warnings.push(`Invalid coerce type "${result.invalidCoerceType}" in @connect. Valid types: string, number, boolean, json, object`);
        delete result.invalidCoerceType;
    }
    return result;
}
/**
 * Get serialized grammar for documentation/diagram generation.
 */
export function getConnectGrammar() {
    return parserInstance.getSerializedGastProductions();
}
//# sourceMappingURL=connect-parser.js.map