"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlueprintEngine = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const glob_1 = require("glob");
const core_1 = require("@myycontext/core");
const OperationExecutor_1 = require("./OperationExecutor");
class BlueprintEngine {
    constructor(baseDir) {
        this.baseDir = baseDir || process.cwd();
        this.executor = new OperationExecutor_1.OperationExecutor(this.baseDir);
    }
    /**
     * Run structural check against workspace filesystem
     */
    async check(blueprint) {
        const violations = [];
        const weights = blueprint.severityWeight || { high: 20, medium: 10, low: 3 };
        // 1. Check directories
        if (blueprint.directories?.required) {
            for (const dir of blueprint.directories.required) {
                const fullPath = path.join(this.baseDir, dir);
                const exists = await fs.pathExists(fullPath);
                if (!exists) {
                    violations.push({
                        id: `dir-missing-${dir}`,
                        type: "directory_missing",
                        severity: "medium",
                        path: dir,
                        description: `Required directory is missing: ${dir}`,
                        expected: `Directory ${dir} exists`,
                        autoFixable: true,
                        requiresHumanReview: false,
                        fixOperation: "create-file" // Handled by creating a .gitkeep file inside the directory
                    });
                }
            }
        }
        // 2. Check files
        if (blueprint.files?.required) {
            for (const fileReq of blueprint.files.required) {
                const fullPath = path.join(this.baseDir, fileReq.path);
                const exists = await fs.pathExists(fullPath);
                if (!exists) {
                    violations.push({
                        id: `file-missing-${fileReq.path}`,
                        type: "file_missing",
                        severity: fileReq.severity,
                        path: fileReq.path,
                        description: fileReq.description || `Required file is missing: ${fileReq.path}`,
                        expected: fileReq.expectedContent || "",
                        autoFixable: fileReq.autoFixable,
                        requiresHumanReview: fileReq.requiresHumanReview,
                        fixOperation: fileReq.fixOperation || "create-file"
                    });
                }
                else if (fileReq.expectedContent) {
                    try {
                        const content = await fs.readFile(fullPath, "utf-8");
                        // Check if expectedContent is a substring of the file contents
                        if (!content.includes(fileReq.expectedContent)) {
                            violations.push({
                                id: `file-mismatch-${fileReq.path}`,
                                type: "file_content_mismatch",
                                severity: fileReq.severity,
                                path: fileReq.path,
                                description: `Required file content mismatch: ${fileReq.path}`,
                                expected: fileReq.expectedContent,
                                actual: content.substring(0, 1000), // Truncate actual content to avoid bloated logs
                                autoFixable: fileReq.autoFixable,
                                requiresHumanReview: fileReq.requiresHumanReview,
                                fixOperation: "patch-file" // Can be auto-fixed by writing/overwriting
                            });
                        }
                    }
                    catch (err) {
                        violations.push({
                            id: `file-read-error-${fileReq.path}`,
                            type: "file_content_mismatch",
                            severity: fileReq.severity,
                            path: fileReq.path,
                            description: `Error reading file ${fileReq.path}: ${err.message}`,
                            autoFixable: false,
                            requiresHumanReview: true
                        });
                    }
                }
            }
        }
        // 3. Check conventions
        if (blueprint.conventions) {
            for (const rule of blueprint.conventions) {
                try {
                    const files = (0, glob_1.globSync)(rule.pathPattern, { cwd: this.baseDir });
                    if (files.length === 0) {
                        violations.push({
                            id: `convention-violation-${rule.id}`,
                            type: "convention_violation",
                            severity: rule.severity,
                            description: `Convention violation [${rule.name}]: ${rule.description}`,
                            expected: `At least one file matching pattern: ${rule.pathPattern}`,
                            autoFixable: false,
                            requiresHumanReview: true
                        });
                    }
                }
                catch (err) {
                    violations.push({
                        id: `convention-glob-error-${rule.id}`,
                        type: "convention_violation",
                        severity: rule.severity,
                        description: `Glob match failed for pattern [${rule.pathPattern}]: ${err.message}`,
                        autoFixable: false,
                        requiresHumanReview: true
                    });
                }
            }
        }
        // Calculate score
        let deduction = 0;
        for (const v of violations) {
            const weight = weights[v.severity] ?? 10;
            deduction += weight;
        }
        const score = Math.max(0, 100 - deduction);
        // Compile operations list for fixable items
        const operations = this.planFromViolations(violations);
        return {
            blueprintId: blueprint.blueprintId,
            score,
            violations,
            operations
        };
    }
    /**
     * Plan operations for a report
     */
    plan(report, blueprint) {
        return report.operations;
    }
    /**
     * Compile operations required to fix violations
     */
    planFromViolations(violations) {
        const ops = [];
        for (const v of violations) {
            if (!v.autoFixable || !v.path)
                continue;
            if (v.type === "directory_missing") {
                // Scaffolding directories is done by placing a .gitkeep file inside them
                const keepPath = path.join(v.path, ".gitkeep");
                ops.push((0, core_1.createOperation)("create-file", `Create PWA directory anchor: ${keepPath}`, {
                    path: keepPath,
                    content: "",
                    overwrite: true
                }));
            }
            else if (v.type === "file_missing" || v.type === "file_content_mismatch") {
                ops.push((0, core_1.createOperation)("create-file", `Align blueprint configuration file: ${v.path}`, {
                    path: v.path,
                    content: v.expected || "",
                    overwrite: true
                }));
            }
        }
        return ops;
    }
    /**
     * Scaffold the entire project blueprint from scratch
     */
    scaffold(blueprint) {
        const ops = [];
        // Create required directories using .gitkeep file operations
        if (blueprint.directories?.required) {
            for (const dir of blueprint.directories.required) {
                const keepPath = path.join(dir, ".gitkeep");
                ops.push((0, core_1.createOperation)("create-file", `Scaffold directory structure: ${dir}/`, {
                    path: keepPath,
                    content: "",
                    overwrite: true
                }));
            }
        }
        // Create required files
        if (blueprint.files?.required) {
            for (const fileReq of blueprint.files.required) {
                ops.push((0, core_1.createOperation)("create-file", `Scaffold blueprint template file: ${fileReq.path}`, {
                    path: fileReq.path,
                    content: fileReq.expectedContent || "",
                    overwrite: true
                }));
            }
        }
        return ops;
    }
    /**
     * Execute operations
     */
    async executeAlign(ops) {
        return this.executor.executeBatch(ops);
    }
}
exports.BlueprintEngine = BlueprintEngine;
//# sourceMappingURL=BlueprintEngine.js.map