const ALLOWED_ATTRS = ['data-dev-name', 'key', 'id', 'name', 'type', 'icon', 'role'];
const SNIPPET_MAX = 24;

export interface SignatureNodeChild {
    type: 'text' | 'interpolation' | 'element' | 'comment';
    content?: string;
}

export interface SignatureNodeProp {
    type: 'attribute' | 'directive';
    name: string;
    value?: string;
    arg?: string;
    exp?: string;
}

export interface SignatureNode {
    tag: string;
    props: SignatureNodeProp[];
    children: SignatureNodeChild[];
}

export interface SignatureContext {
    filePath: string;        // absolute or relative — anything load-time-stable
    appRoot: string;         // e.g. 'app/', used by normalizeFilePath
    ancestorChain: string[]; // ['DeclaringComponent', 'div', 'nav']
    sameTagOrdinal: number;  // 0-based among siblings of same tag in same parent
}

export function normalizeFilePath(filePath: string, appRoot: string): string {
    const normalized = filePath.replace(/\\/g, '/').replace(/\.vue$/, '');
    const root = appRoot.replace(/\\/g, '/').replace(/\/$/, '') + '/';
    return normalized.startsWith(root) ? normalized.slice(root.length) : normalized;
}

export function extractStaticText(node: SignatureNode): string | null {
    const parts: string[] = [];
    for (const child of node.children) {
        if (child.type === 'text' && child.content) {
            parts.push(child.content);
        }
    }
    if (parts.length === 0) return null;
    const merged = parts.join(' ').replace(/\s+/g, ' ').trim().toLowerCase();
    if (!merged) return null;
    return merged.slice(0, SNIPPET_MAX);
}

export function extractDistinctiveAttrs(node: SignatureNode): string {
    const pairs: string[] = [];
    for (const prop of node.props) {
        if (prop.type !== 'attribute') continue;   // skip directives / v-bind
        if (!ALLOWED_ATTRS.includes(prop.name)) continue;
        if (prop.value == null) continue;
        pairs.push(`${prop.name}=${prop.value}`);
    }
    return pairs.sort().join(',');
}

function findDevName(node: SignatureNode): string | null {
    for (const prop of node.props) {
        if (prop.type === 'attribute' && prop.name === 'data-dev-name' && prop.value) {
            return prop.value;
        }
    }
    return null;
}

export function computeSignature(node: SignatureNode, ctx: SignatureContext): string {
    const path = normalizeFilePath(ctx.filePath, ctx.appRoot);
    const devName = findDevName(node);
    if (devName) {
        return `${path}::data-dev-name::${devName}`;
    }
    const ancestors = ctx.ancestorChain.join('>');
    const attrs = extractDistinctiveAttrs(node);
    const text = extractStaticText(node) ?? '';
    return `${path}::${ancestors}::${node.tag}[${attrs}]::${text}::${ctx.sameTagOrdinal}`;
}
