"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pipelineSkillLoader = void 0;
exports.ensurePipelineSkillsInitialized = ensurePipelineSkillsInitialized;
exports.getPipelineSkillLoader = getPipelineSkillLoader;
exports.getAutoPinInstructions = getAutoPinInstructions;
exports.getTeachingContent = getTeachingContent;
exports.getSmartFilterConfigs = getSmartFilterConfigs;
/**
 * Pipeline Skill Loader
 *
 * Loads and manages pipeline skill definitions from YAML files.
 * Pipeline skills contain detection rules, teaching content, auto-pin
 * instructions, and analysis recommendations for each rendering pipeline type.
 *
 * This replaces the hardcoded configurations in trackPinService.ts with
 * a data-driven approach using YAML skill files.
 */
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const js_yaml_1 = __importDefault(require("js-yaml"));
// =============================================================================
// Pipeline Skill Loader
// =============================================================================
class PipelineSkillLoaderClass {
    constructor() {
        this.pipelineCache = new Map();
        this.initialized = false;
        this.pipelinesDir = path_1.default.resolve(__dirname, '../../skills/pipelines');
    }
    validateDetection(pipeline, file) {
        const pipelineId = pipeline?.meta?.pipeline_id || 'UNKNOWN';
        const detection = pipeline.detection;
        if (!detection)
            return;
        const selectorKeys = ['thread', 'thread_pattern', 'slice', 'slice_pattern'];
        const countSelectors = (obj) => selectorKeys.filter((k) => obj[k] !== undefined && obj[k] !== null);
        const validateMinCount = (v) => {
            if (v === undefined || v === null)
                return true;
            const n = typeof v === 'number' ? v : parseInt(String(v), 10);
            return Number.isFinite(n) && n > 0;
        };
        const warn = (msg) => {
            console.warn(`[PipelineSkillLoader] Validation warning in ${file} (${pipelineId}): ${msg}`);
        };
        for (const [kind, items] of [
            ['required_signals', detection.required_signals || []],
            ['exclude_if', detection.exclude_if || []],
        ]) {
            for (const item of items) {
                const keys = countSelectors(item);
                if (keys.length !== 1)
                    warn(`${kind} entry must have exactly one selector, got [${keys.join(', ')}]`);
                if (!validateMinCount(item.min_count))
                    warn(`${kind} entry has invalid min_count: ${item.min_count}`);
            }
        }
        for (const item of detection.scoring_signals || []) {
            const keys = countSelectors(item);
            if (keys.length !== 1)
                warn(`scoring_signals '${item.signal}' must have exactly one selector, got [${keys.join(', ')}]`);
            const signal = item.signal;
            if (!signal || typeof signal !== 'string')
                warn(`scoring_signals entry missing 'signal' name`);
            const weight = item.weight;
            if (typeof weight !== 'number' || !Number.isFinite(weight) || weight < 0) {
                warn(`scoring_signals '${signal || 'UNKNOWN'}' has invalid weight: ${weight}`);
            }
            if (!validateMinCount(item.min_count))
                warn(`scoring_signals '${signal || 'UNKNOWN'}' has invalid min_count: ${item.min_count}`);
        }
        if (!Array.isArray(detection.scoring_signals) || detection.scoring_signals.length === 0) {
            warn('detection.scoring_signals is empty; pipeline will never be selected by scoring');
        }
    }
    /**
     * Load all pipeline skills from the pipelines directory
     */
    async loadPipelines() {
        if (this.initialized)
            return;
        console.log(`[PipelineSkillLoader] Loading pipelines from: ${this.pipelinesDir}`);
        if (!fs_1.default.existsSync(this.pipelinesDir)) {
            console.warn(`[PipelineSkillLoader] Pipelines directory not found: ${this.pipelinesDir}`);
            this.initialized = true;
            return;
        }
        const files = fs_1.default.readdirSync(this.pipelinesDir);
        for (const file of files) {
            // Skip non-skill files (index.yaml, _base.skill.yaml)
            if (!file.endsWith('.skill.yaml') && !file.endsWith('.skill.yml'))
                continue;
            if (file.startsWith('_'))
                continue;
            const filePath = path_1.default.join(this.pipelinesDir, file);
            try {
                const content = fs_1.default.readFileSync(filePath, 'utf-8');
                const pipeline = js_yaml_1.default.load(content);
                if (pipeline && pipeline.meta?.pipeline_id) {
                    this.validateDetection(pipeline, file);
                    this.pipelineCache.set(pipeline.meta.pipeline_id, pipeline);
                    console.log(`[PipelineSkillLoader] Loaded pipeline: ${pipeline.meta.pipeline_id} (${pipeline.meta.display_name})`);
                }
            }
            catch (error) {
                console.error(`[PipelineSkillLoader] Failed to load ${file}:`, error.message);
            }
        }
        this.initialized = true;
        console.log(`[PipelineSkillLoader] Loaded ${this.pipelineCache.size} pipeline definitions`);
    }
    /**
     * Get a pipeline definition by ID
     */
    getPipeline(pipelineId) {
        return this.pipelineCache.get(pipelineId) || null;
    }
    /**
     * Get all loaded pipelines
     */
    getAllPipelines() {
        return Array.from(this.pipelineCache.values());
    }
    /**
     * Get all pipeline IDs
     */
    getAllPipelineIds() {
        return Array.from(this.pipelineCache.keys());
    }
    /**
     * Get auto-pin instructions for a pipeline
     */
    getAutoPinInstructions(pipelineId) {
        const pipeline = this.getPipeline(pipelineId);
        if (!pipeline) {
            console.warn(`[PipelineSkillLoader] Pipeline not found: ${pipelineId}, using default`);
            return this.getDefaultPinInstructions();
        }
        return pipeline.auto_pin?.instructions || this.getDefaultPinInstructions();
    }
    /**
     * Get smart filter configurations for a pipeline
     * Returns a map of pattern -> SmartFilterConfig
     */
    getSmartFilterConfigs(pipelineId) {
        const configs = new Map();
        const pipeline = this.getPipeline(pipelineId);
        if (!pipeline)
            return configs;
        for (const inst of pipeline.auto_pin?.instructions || []) {
            if (inst.smart_filter?.enabled) {
                configs.set(inst.pattern, inst.smart_filter);
            }
        }
        return configs;
    }
    /**
     * Get teaching content for a pipeline
     */
    getTeachingContent(pipelineId) {
        const pipeline = this.getPipeline(pipelineId);
        return pipeline?.teaching || null;
    }
    /**
     * Get pipeline meta information
     */
    getPipelineMeta(pipelineId) {
        const pipeline = this.getPipeline(pipelineId);
        return pipeline?.meta || null;
    }
    /**
     * Get recommended skills for a pipeline
     */
    getRecommendedSkills(pipelineId) {
        const pipeline = this.getPipeline(pipelineId);
        return pipeline?.analysis?.recommended_skills || [];
    }
    /**
     * Get common issues for a pipeline
     */
    getCommonIssues(pipelineId) {
        const pipeline = this.getPipeline(pipelineId);
        return pipeline?.analysis?.common_issues || [];
    }
    /**
     * Check if loader is initialized
     */
    isInitialized() {
        return this.initialized;
    }
    /**
     * Reload all pipeline skills
     */
    async reload() {
        this.pipelineCache.clear();
        this.initialized = false;
        await this.loadPipelines();
    }
    /**
     * Default pin instructions for fallback
     */
    getDefaultPinInstructions() {
        return [
            {
                pattern: '^VSYNC-app$',
                match_by: 'name',
                priority: 1,
                reason: 'VSync (App 开始生产帧)',
            },
            {
                pattern: '^main(\\s+\\d+)?$',
                match_by: 'name',
                priority: 2,
                reason: 'App 主线程',
            },
            {
                pattern: '^RenderThread(\\s+\\d+)?$',
                match_by: 'name',
                priority: 3,
                reason: 'App 渲染线程 (RenderThread)',
            },
            {
                pattern: '^VSYNC-sf$',
                match_by: 'name',
                priority: 5.5,
                reason: 'VSync (SurfaceFlinger 消费/合成)',
            },
            {
                pattern: '^SurfaceFlinger$',
                match_by: 'name',
                priority: 7,
                reason: 'SurfaceFlinger (最终合成/显示)',
            },
        ];
    }
}
// =============================================================================
// Singleton and Helper Functions
// =============================================================================
exports.pipelineSkillLoader = new PipelineSkillLoaderClass();
// Promise-based lock to prevent concurrent initialization
let initializationPromise = null;
/**
 * Ensure pipeline skill loader is initialized
 * Safe to call concurrently - will only initialize once
 */
async function ensurePipelineSkillsInitialized() {
    // Fast path: already initialized
    if (exports.pipelineSkillLoader.isInitialized())
        return;
    // If initialization is in progress, wait for it
    if (initializationPromise) {
        await initializationPromise;
        return;
    }
    // Start initialization
    initializationPromise = exports.pipelineSkillLoader.loadPipelines();
    try {
        await initializationPromise;
    }
    finally {
        if (!exports.pipelineSkillLoader.isInitialized()) {
            initializationPromise = null;
        }
    }
}
/**
 * Get pipeline skill loader instance
 */
function getPipelineSkillLoader() {
    return exports.pipelineSkillLoader;
}
/**
 * Convenience function to get auto-pin instructions
 */
async function getAutoPinInstructions(pipelineId) {
    await ensurePipelineSkillsInitialized();
    return exports.pipelineSkillLoader.getAutoPinInstructions(pipelineId);
}
/**
 * Convenience function to get teaching content
 */
async function getTeachingContent(pipelineId) {
    await ensurePipelineSkillsInitialized();
    return exports.pipelineSkillLoader.getTeachingContent(pipelineId);
}
/**
 * Convenience function to get smart filter configs
 */
async function getSmartFilterConfigs(pipelineId) {
    await ensurePipelineSkillsInitialized();
    return exports.pipelineSkillLoader.getSmartFilterConfigs(pipelineId);
}
//# sourceMappingURL=pipelineSkillLoader.js.map