import fs from "node:fs";
import path from "node:path";
import { bobbitStateDir } from "../bobbit-dir.js";
export const WALKTHROUGH_STORE_SCHEMA_VERSION = 1;
const STORE_DIR = "pr-walkthrough";
export function storeWalkthrough(payload, stateDir = bobbitStateDir()) {
    return new WalkthroughStore(stateDir).save(payload);
}
export function saveWalkthrough(payload, stateDir = bobbitStateDir()) {
    return storeWalkthrough(payload, stateDir);
}
export function loadWalkthrough(changesetId, stateDir = bobbitStateDir()) {
    return new WalkthroughStore(stateDir).get(changesetId);
}
export function getWalkthrough(changesetId, stateDir = bobbitStateDir()) {
    return loadWalkthrough(changesetId, stateDir);
}
export class WalkthroughStore {
    rootDir;
    constructor(stateDir) {
        this.rootDir = path.join(stateDir, STORE_DIR, `v${WALKTHROUGH_STORE_SCHEMA_VERSION}`);
    }
    save(payload) {
        const stored = sanitizePayload({
            ...payload,
            warnings: payload.warnings ?? [],
            schemaVersion: WALKTHROUGH_STORE_SCHEMA_VERSION,
            updatedAt: new Date().toISOString(),
        });
        this.ensureDir();
        fs.writeFileSync(this.filePath(payload.changesetId), `${JSON.stringify(stored, null, 2)}\n`, "utf-8");
        return stored;
    }
    get(changesetId) {
        try {
            const raw = JSON.parse(fs.readFileSync(this.filePath(changesetId), "utf-8"));
            return parseStoredPayload(raw, changesetId);
        }
        catch (error) {
            if (isNodeError(error) && error.code === "ENOENT")
                return null;
            return null;
        }
    }
    delete(changesetId) {
        try {
            fs.unlinkSync(this.filePath(changesetId));
            return true;
        }
        catch (error) {
            if (isNodeError(error) && error.code === "ENOENT")
                return false;
            return false;
        }
    }
    list() {
        try {
            return fs.readdirSync(this.rootDir, { withFileTypes: true })
                .filter(entry => entry.isFile() && entry.name.endsWith(".json"))
                .map(entry => this.readFile(path.join(this.rootDir, entry.name)))
                .filter((payload) => payload !== null)
                .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
        }
        catch (error) {
            if (isNodeError(error) && error.code === "ENOENT")
                return [];
            return [];
        }
    }
    readFile(filePath) {
        try {
            const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
            return parseStoredPayload(raw);
        }
        catch {
            return null;
        }
    }
    ensureDir() {
        fs.mkdirSync(this.rootDir, { recursive: true });
    }
    filePath(changesetId) {
        return path.join(this.rootDir, `${storageKeyForChangesetId(changesetId)}.json`);
    }
}
export function storageKeyForChangesetId(changesetId) {
    return Buffer.from(changesetId, "utf-8").toString("base64url");
}
function parseStoredPayload(raw, expectedChangesetId) {
    if (raw.schemaVersion !== WALKTHROUGH_STORE_SCHEMA_VERSION)
        return null;
    if (typeof raw.updatedAt !== "string" || typeof raw.changesetId !== "string")
        return null;
    if (expectedChangesetId && raw.changesetId !== expectedChangesetId)
        return null;
    if (!isRecord(raw.changeset) || !Array.isArray(raw.cards))
        return null;
    const warnings = Array.isArray(raw.warnings) ? raw.warnings : [];
    return sanitizePayload({
        changesetId: raw.changesetId,
        changeset: raw.changeset,
        cards: raw.cards,
        warnings: warnings,
        limits: isRecord(raw.limits) ? raw.limits : undefined,
        export: isRecord(raw.export) ? raw.export : undefined,
        schemaVersion: WALKTHROUGH_STORE_SCHEMA_VERSION,
        updatedAt: raw.updatedAt,
    });
}
function sanitizePayload(payload) {
    const sanitized = sanitizeValue(payload);
    return sanitized;
}
function sanitizeValue(value) {
    if (Array.isArray(value))
        return value.map(item => sanitizeValue(item));
    if (!isRecord(value))
        return value;
    const out = {};
    for (const [key, entry] of Object.entries(value)) {
        if (isSensitiveKey(key))
            continue;
        out[key] = sanitizeValue(entry);
    }
    return out;
}
function isSensitiveKey(key) {
    return /(^|[-_])(token|secret|authorization|auth[-_]?header|auth[-_]?headers|raw[-_]?headers|headers?)($|[-_])/i.test(key)
        || /^(token|secret|authorization|auth|headers)$/i.test(key);
}
function isRecord(value) {
    return typeof value === "object" && value !== null;
}
function isNodeError(error) {
    return error instanceof Error && "code" in error;
}
//# sourceMappingURL=walkthrough-store.js.map