"use strict";
/**
 * In-memory registry store for demo / static mode (no Postgres required).
 */
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.MemoryDB = void 0;
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class MemoryDB {
    packages = [];
    versions = [];
    users = [];
    sessions = new Map();
    apiKeys = [];
    trusted = [];
    audit = [];
    reports = [];
    deps = new Map();
    owners = new Map();
    orgs = [];
    nextPkg = 1;
    nextVer = 1;
    nextUser = 1;
    seedFromStorage(storageDir) {
        if (!fs.existsSync(storageDir)) {
            this.seedDefaults();
            return;
        }
        const now = new Date().toISOString();
        let found = false;
        for (const name of fs.readdirSync(storageDir)) {
            const pkgDir = path.join(storageDir, name);
            if (!fs.statSync(pkgDir).isDirectory()) {
                continue;
            }
            for (const ver of fs.readdirSync(pkgDir)) {
                const verDir = path.join(pkgDir, ver);
                if (!fs.statSync(verDir).isDirectory()) {
                    continue;
                }
                const files = fs.readdirSync(verDir).filter((f) => f.endsWith(".nex"));
                if (files.length === 0) {
                    continue;
                }
                const filename = files[0];
                const storagePath = path.join(verDir, filename);
                const data = fs.readFileSync(storagePath);
                const checksum = "sha256:" + crypto.createHash("sha256").update(data).digest("hex");
                let pkg = this.packages.find((p) => p.Name === name);
                if (!pkg) {
                    pkg = {
                        ID: this.nextPkg++,
                        Name: name,
                        Description: `${name} package for Nexus`,
                        Author: "nexus",
                        License: "MIT",
                        Repository: "",
                        Homepage: "",
                        Keywords: [name, "nex"],
                        Categories: name === "httpkit" ? ["network"] : ["web"],
                        Readme: `# ${name}\n\nDemo package seeded from \`storage/\`.\n\nInstall with \`nex install ${name}@${ver}\`.\n`,
                        DownloadCount: 42,
                        OwnerID: null,
                        OwnerUsername: "nexus",
                        CreatedAt: now,
                        UpdatedAt: now,
                        LatestVersion: ver,
                    };
                    this.packages.push(pkg);
                }
                const version = {
                    ID: this.nextVer++,
                    PackageID: pkg.ID,
                    Version: ver,
                    Checksum: checksum,
                    StoragePath: storagePath,
                    Filename: filename,
                    FileSize: data.length,
                    ContentType: "application/octet-stream",
                    Yanked: false,
                    YankReason: "",
                    Deprecated: false,
                    DeprecationMessage: "",
                    CreatedAt: now,
                };
                this.versions.push(version);
                pkg.LatestVersion = ver;
                pkg.UpdatedAt = now;
                found = true;
            }
        }
        if (!found) {
            this.seedDefaults();
        }
    }
    seedDefaults() {
        const now = new Date().toISOString();
        const pkg = {
            ID: this.nextPkg++,
            Name: "httpkit",
            Description: "Tiny HTTP helpers for Nexus",
            Author: "nexus",
            License: "MIT",
            Repository: "",
            Homepage: "",
            Keywords: ["http", "net"],
            Categories: ["network"],
            Readme: "# httpkit\n\nTiny HTTP helpers for Nexus apps.\n",
            DownloadCount: 128,
            OwnerID: null,
            OwnerUsername: "nexus",
            CreatedAt: now,
            UpdatedAt: now,
            LatestVersion: "1.0.0",
        };
        this.packages.push(pkg);
        this.versions.push({
            ID: this.nextVer++,
            PackageID: pkg.ID,
            Version: "1.0.0",
            Checksum: "sha256:demo",
            StoragePath: "",
            Filename: "httpkit-1.0.0.nex",
            FileSize: 32,
            ContentType: "application/octet-stream",
            Yanked: false,
            YankReason: "",
            Deprecated: false,
            DeprecationMessage: "",
            CreatedAt: now,
        });
    }
    hubStats() {
        return {
            Packages: this.packages.length,
            Versions: this.versions.length,
            Downloads: this.packages.reduce((a, p) => a + p.DownloadCount, 0),
            Users: Math.max(this.users.length, 1),
            Tags: this.topTags(16),
        };
    }
    topTags(limit) {
        const counts = new Map();
        for (const p of this.packages) {
            for (const t of [...p.Keywords, ...p.Categories]) {
                counts.set(t, (counts.get(t) ?? 0) + 1);
            }
        }
        return [...counts.entries()]
            .sort((a, b) => b[1] - a[1])
            .slice(0, limit)
            .map(([Name, Count]) => ({ Name, Count }));
    }
    topKeywords(limit) {
        return this.topTags(limit).map((t) => ({ ...t, Keyword: t.Name }));
    }
    listLicenses(limit) {
        const counts = new Map();
        for (const p of this.packages) {
            if (p.License) {
                counts.set(p.License, (counts.get(p.License) ?? 0) + 1);
            }
        }
        return [...counts.entries()]
            .slice(0, limit)
            .map(([Name, Count]) => ({ Name, Count, License: Name }));
    }
    listRecent(limit) {
        return [...this.packages]
            .sort((a, b) => (a.UpdatedAt < b.UpdatedAt ? 1 : -1))
            .slice(0, limit)
            .map((p) => ({ ...p }));
    }
    listPopular(limit) {
        return [...this.packages]
            .sort((a, b) => b.DownloadCount - a.DownloadCount)
            .slice(0, limit)
            .map((p) => ({ ...p }));
    }
    search(opts) {
        const q = String(opts.q ?? opts.query ?? "").toLowerCase();
        const category = String(opts.category ?? "").toLowerCase();
        const keyword = String(opts.keyword ?? "").toLowerCase();
        const license = String(opts.license ?? "");
        const sort = String(opts.sort ?? "relevance");
        const limit = Number(opts.limit ?? 50);
        const offset = Number(opts.offset ?? 0);
        const browse = Boolean(opts.browse);
        let rows = [...this.packages];
        if (q) {
            rows = rows.filter((p) => p.Name.toLowerCase().includes(q) ||
                p.Description.toLowerCase().includes(q) ||
                p.Keywords.some((k) => k.toLowerCase().includes(q)));
        }
        if (category) {
            rows = rows.filter((p) => p.Categories.some((c) => c.toLowerCase() === category));
        }
        if (keyword) {
            rows = rows.filter((p) => p.Keywords.some((k) => k.toLowerCase() === keyword));
        }
        if (license) {
            rows = rows.filter((p) => p.License === license);
        }
        if (!browse && !q && !category && !keyword && !license) {
            rows = [];
        }
        if (sort === "downloads") {
            rows.sort((a, b) => b.DownloadCount - a.DownloadCount);
        }
        else if (sort === "recent") {
            rows.sort((a, b) => (a.UpdatedAt < b.UpdatedAt ? 1 : -1));
        }
        else {
            rows.sort((a, b) => a.Name.localeCompare(b.Name));
        }
        const total = rows.length;
        const packages = rows.slice(offset, offset + limit).map((p) => ({ ...p }));
        return {
            packages,
            total,
            query: q,
            category,
            keyword,
            license,
            sort,
            limit,
            offset,
        };
    }
    getPackage(name) {
        return this.packages.find((p) => p.Name === name) ?? null;
    }
    listVersions(packageId) {
        return this.versions
            .filter((v) => v.PackageID === packageId)
            .sort((a, b) => (a.CreatedAt < b.CreatedAt ? 1 : -1));
    }
    getPackageVersion(name, version) {
        const pkg = this.getPackage(name);
        if (!pkg) {
            return null;
        }
        const ver = this.versions.find((v) => v.PackageID === pkg.ID && v.Version === version);
        if (!ver) {
            return null;
        }
        return { Package: pkg, Version: ver };
    }
    createUser(username, email, passwordHash, avatar = "", bio = "", useGravatar = false) {
        const now = new Date().toISOString();
        const id = this.nextUser++;
        const u = {
            id,
            ID: id,
            username,
            Username: username,
            email,
            Email: email,
            password_hash: passwordHash,
            avatar_url: avatar,
            AvatarURL: avatar,
            bio,
            Bio: bio,
            use_gravatar: useGravatar,
            UseGravatar: useGravatar,
            github_id: null,
            github_login: "",
            GitHubLogin: "",
            has_password: true,
            HasPassword: true,
            email_verified: false,
            EmailVerified: false,
            totp_enabled: false,
            TOTPEnabled: false,
            is_admin: false,
            IsAdmin: false,
            created_at: now,
            CreatedAt: now,
        };
        this.users.push(u);
        return u;
    }
    getUser(username) {
        return (this.users.find((u) => u.username === username ||
            u.email.toLowerCase() === username.toLowerCase()) ?? null);
    }
    getUserById(id) {
        return this.users.find((u) => u.id === id) ?? null;
    }
    createSession(userId) {
        const token = "nxs_" + crypto.randomBytes(24).toString("hex");
        this.sessions.set(token, userId);
        return token;
    }
    userFromSession(token) {
        const id = this.sessions.get(token);
        if (id === undefined) {
            return null;
        }
        return this.getUserById(id);
    }
    deleteSession(token) {
        this.sessions.delete(token);
    }
}
exports.MemoryDB = MemoryDB;
//# sourceMappingURL=db_memory.js.map