import { now } from './_util';
export class LocalKeyValueStorage {
    #db;
    #projectPath;
    constructor(db, projectPath) {
        this.#db = db;
        this.#projectPath = projectPath;
    }
    async get(name, key) {
        const query = this.#db.query(`
			SELECT value, content_type, expires_at 
			FROM kv_storage 
			WHERE project_path = ? AND name = ? AND key = ?
		`);
        const row = query.get(this.#projectPath, name, key);
        if (!row) {
            return { exists: false };
        }
        // Check expiration
        if (row.expires_at && row.expires_at < now()) {
            // Delete expired row
            await this.delete(name, key);
            return { exists: false };
        }
        // Deserialize based on content type
        let data;
        if (row.content_type === 'application/json') {
            try {
                const text = row.value.toString('utf-8');
                data = JSON.parse(text);
            }
            catch {
                // If JSON parse fails, return the raw buffer as Uint8Array
                data = new Uint8Array(row.value);
            }
        }
        else if (row.content_type.startsWith('text/')) {
            data = row.value.toString('utf-8');
        }
        else {
            data = new Uint8Array(row.value);
        }
        return {
            data,
            contentType: row.content_type,
            exists: true,
            // Include expiresAt if set (convert from Unix timestamp to ISO string)
            ...(row.expires_at && { expiresAt: new Date(row.expires_at).toISOString() }),
        };
    }
    async set(name, key, value, params) {
        // Serialize value
        let buffer;
        let contentType = params?.contentType || 'application/octet-stream';
        if (typeof value === 'string') {
            buffer = Buffer.from(value, 'utf-8');
            if (!params?.contentType) {
                contentType = 'text/plain';
            }
        }
        else if (value instanceof Uint8Array) {
            buffer = Buffer.from(value);
        }
        else if (value instanceof ArrayBuffer) {
            buffer = Buffer.from(new Uint8Array(value));
        }
        else if (typeof value === 'number' ||
            typeof value === 'boolean' ||
            typeof value === 'object') {
            // Use JSON for numbers, booleans, and objects to preserve type on round-trip
            buffer = Buffer.from(JSON.stringify(value), 'utf-8');
            contentType = 'application/json';
        }
        else {
            // Fallback for other types
            buffer = Buffer.from(String(value), 'utf-8');
        }
        // Calculate expiration
        // TTL handling: null or 0 = no expiration, positive = TTL in seconds
        // undefined = use default (7 days for consistency with cloud namespace default)
        let expiresAt = null;
        if (params?.ttl === undefined) {
            // Default to 7 days (matching cloud namespace default behavior)
            expiresAt = now() + 7 * 24 * 60 * 60 * 1000;
        }
        else if (params.ttl !== null && params.ttl > 0) {
            expiresAt = now() + params.ttl * 1000;
        }
        // else: ttl is null or 0, so expiresAt stays null (no expiration)
        const timestamp = now();
        // UPSERT
        const stmt = this.#db.prepare(`
			INSERT INTO kv_storage (project_path, name, key, value, content_type, expires_at, created_at, updated_at)
			VALUES (?, ?, ?, ?, ?, ?, ?, ?)
			ON CONFLICT(project_path, name, key) 
			DO UPDATE SET 
				value = excluded.value,
				content_type = excluded.content_type,
				expires_at = excluded.expires_at,
				updated_at = excluded.updated_at
		`);
        stmt.run(this.#projectPath, name, key, buffer, contentType, expiresAt, timestamp, timestamp);
    }
    async delete(name, key) {
        const stmt = this.#db.prepare(`
			DELETE FROM kv_storage 
			WHERE project_path = ? AND name = ? AND key = ?
		`);
        stmt.run(this.#projectPath, name, key);
    }
    async getStats(_name) {
        throw new Error('getStats not implemented for local storage');
    }
    async getAllStats(_params) {
        throw new Error('getAllStats not implemented for local storage');
    }
    async getNamespaces() {
        throw new Error('getNamespaces not implemented for local storage');
    }
    async search(_name, _keyword) {
        throw new Error('search not implemented for local storage');
    }
    async getKeys(_name) {
        throw new Error('getKeys not implemented for local storage');
    }
    async deleteNamespace(_name) {
        throw new Error('deleteNamespace not implemented for local storage');
    }
    async createNamespace(_name, _params) {
        throw new Error('createNamespace not implemented for local storage');
    }
}
//# sourceMappingURL=keyvalue.js.map