"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.RegistryBuilder = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const child_process_1 = require("child_process");
const crypto_1 = require("crypto");
const IGNORE_DIRS = new Set([
    "node_modules", ".next", ".git", "dist", "build", ".turbo",
    ".pnpm-store", "coverage", ".cache", ".vercel", "__pycache__",
    "storybook-static", "out", ".expo", ".server", ".client",
]);
const IGNORE_EXTENSIONS = new Set([
    ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2",
    ".ttf", ".eot", ".mp4", ".webm", ".mp3", ".wav", ".pdf", ".lock",
    ".map", ".webp", ".avif", ".bmp", ".tiff",
    ".log", ".DS_Store",
]);
class RegistryBuilder {
    constructor(projectRoot = process.cwd()) {
        this.projectRoot = projectRoot;
    }
    async build() {
        const allFiles = this.discoverFiles();
        const contextOwnership = await this.loadContextOwnership();
        const registry = {};
        for (const filePath of allFiles) {
            const entry = this.classifyFile(filePath, contextOwnership);
            if (entry.status === "tracked" || entry.status === "untracked") {
                entry.hash = await this.hashFile(filePath);
            }
            registry[filePath] = entry;
        }
        return {
            version: "1",
            generatedAt: new Date().toISOString(),
            projectRoot: this.projectRoot,
            files: registry,
        };
    }
    discoverFiles() {
        try {
            const out = (0, child_process_1.execSync)("git ls-files --cached --others --exclude-standard", {
                cwd: this.projectRoot,
                stdio: ["ignore", "pipe", "ignore"],
                encoding: "utf8",
                timeout: 10000,
            });
            return out.trim().split("\n").filter(Boolean);
        }
        catch {
            return this.fallbackWalk();
        }
    }
    fallbackWalk() {
        const files = [];
        const walk = (dir, depth) => {
            if (depth > 8)
                return;
            let items;
            try {
                items = fs.readdirSync(dir);
            }
            catch {
                return;
            }
            for (const item of items) {
                const abs = path.join(dir, item);
                const rel = path.relative(this.projectRoot, abs);
                if (IGNORE_DIRS.has(item) || item.startsWith("."))
                    continue;
                try {
                    const stat = fs.statSync(abs);
                    if (stat.isDirectory()) {
                        walk(abs, depth + 1);
                    }
                    else if (stat.isFile()) {
                        const ext = path.extname(item);
                        if (!IGNORE_EXTENSIONS.has(ext)) {
                            files.push(rel);
                        }
                    }
                }
                catch {
                    // skip
                }
            }
        };
        for (const top of ["apps", "packages", "src", "lib"]) {
            const topPath = path.join(this.projectRoot, top);
            if (fs.existsSync(topPath))
                walk(topPath, 0);
        }
        return files;
    }
    async loadContextOwnership() {
        const owned = new Set();
        try {
            const brain = await fs.readJson(path.join(this.projectRoot, ".mycontext", "context.json"));
            const features = brain.features || brain.phases?.implementation_plan?.features || [];
            for (const feature of features) {
                const ownership = feature.ownership || {};
                for (const key of ["routes", "components", "actions", "models", "permissions", "i18n", "tests"]) {
                    const paths = ownership[key] || [];
                    for (const p of paths) {
                        owned.add(p.replace(/^\//, ""));
                    }
                }
            }
        }
        catch {
            // No context.json yet
        }
        return owned;
    }
    classifyFile(filePath, ownedPaths) {
        // Check if file is in an ignored directory
        const parts = filePath.split("/");
        for (const part of parts) {
            if (IGNORE_DIRS.has(part)) {
                return { status: "ignored", reason: `in ignored directory: ${part}` };
            }
        }
        // Context files are tracked (must check before hidden-file rule)
        if (filePath.startsWith(".mycontext/")) {
            return { status: "tracked", ref: [".mycontext"] };
        }
        // Hidden files are ignored (except specific ones)
        if (parts.some((p) => p.startsWith(".") && p !== ".env.example")) {
            return { status: "ignored", reason: "hidden file" };
        }
        // Binary/media extensions
        const ext = path.extname(filePath).toLowerCase();
        if (IGNORE_EXTENSIONS.has(ext)) {
            return { status: "ignored", reason: `binary/media extension: ${ext}` };
        }
        // Owned by context.json
        if (ownedPaths.has(filePath)) {
            return { status: "tracked" };
        }
        // Source files
        const sourceExts = new Set([
            ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
            ".json", ".yaml", ".yml", ".toml",
            ".css", ".scss", ".less", ".module.css",
            ".md", ".mdx",
            ".graphql", ".gql",
            ".prisma",
        ]);
        if (sourceExts.has(ext)) {
            return { status: "untracked" };
        }
        // Everything else ignored
        return { status: "ignored", reason: "non-source file" };
    }
    async hashFile(filePath) {
        try {
            const content = await fs.readFile(path.join(this.projectRoot, filePath));
            return (0, crypto_1.createHash)("sha256").update(content).digest("hex").substring(0, 12);
        }
        catch {
            return "error";
        }
    }
    async write(registry) {
        const dir = path.join(this.projectRoot, ".mycontext");
        await fs.ensureDir(dir);
        await fs.writeJson(path.join(dir, "file-registry.json"), registry, { spaces: 2 });
    }
    async read() {
        try {
            return await fs.readJson(path.join(this.projectRoot, ".mycontext", "file-registry.json"));
        }
        catch {
            return null;
        }
    }
}
exports.RegistryBuilder = RegistryBuilder;
//# sourceMappingURL=RegistryBuilder.js.map