import { permissionDecisionSelectSql } from "../internal/sql.js";
import { isPermissionSessionDecisionActivity, isRecord, mapPermissionDecision, } from "../internal/rowMappers.js";
import { clampLimit, decodePermissionDecisionCursor, encodePermissionDecisionCursor, } from "../internal/cursors.js";
export class PermissionDecisionRepository {
    #db;
    #activity;
    constructor(db, activity) {
        this.#db = db;
        this.#activity = activity;
    }
    insertPermissionDecision(input) {
        const now = new Date().toISOString();
        this.#db
            .prepare(`INSERT INTO permission_decisions
           (id, workspace_id, run_id, runtime_session_id, scope, effect, option, capabilities_json, pattern, tool_name, tool_title, tool_risk, input_preview, affected_paths_json, source_permission_request_id, audit_id, status, created_at, updated_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?)`)
            .run(input.id, input.workspaceId, input.runId ?? null, input.runtimeSessionId ?? null, input.scope, input.effect, input.option, JSON.stringify(input.capabilities), input.pattern, input.toolName, input.toolTitle, input.toolRisk, input.inputPreview.slice(0, 500), JSON.stringify(input.affectedPaths ?? []), input.sourcePermissionRequestId ?? null, input.auditId, now, now);
        const decision = this.getPermissionDecision(input.id);
        if (isPermissionSessionDecisionActivity(decision)) {
            this.#activity.appendPermissionDecisionActivityEvent(decision, {
                kind: "session_decision_recorded",
                activityAt: now,
                status: "active",
            });
        }
        return decision;
    }
    findPermissionDecision(id) {
        const decision = this.#db
            .prepare(permissionDecisionSelectSql("WHERE id = ?"))
            .get(id);
        return isRecord(decision) ? mapPermissionDecision(decision) : undefined;
    }
    listPermissionDecisions(options) {
        const limit = clampLimit(options.limit ?? 50);
        const cursor = decodePermissionDecisionCursor(options.cursor);
        const clauses = ["workspace_id = ?"];
        const params = [options.workspaceId];
        if (options.status) {
            clauses.push("status = ?");
            params.push(options.status);
        }
        if (options.runId) {
            clauses.push("run_id = ?");
            params.push(options.runId);
        }
        if (options.scope) {
            clauses.push("scope = ?");
            params.push(options.scope);
        }
        if (options.effect) {
            clauses.push("effect = ?");
            params.push(options.effect);
        }
        if (options.option) {
            clauses.push("option = ?");
            params.push(options.option);
        }
        if (cursor) {
            clauses.push("(created_at > ? OR (created_at = ? AND id > ?))");
            params.push(cursor.createdAt, cursor.createdAt, cursor.id);
        }
        const rows = this.#db
            .prepare(`${permissionDecisionSelectSql(`WHERE ${clauses.join(" AND ")}`)} ORDER BY created_at ASC, id ASC LIMIT ?`)
            .all(...params, limit + 1);
        const mapped = rows.map(mapPermissionDecision);
        const decisions = mapped.slice(0, limit);
        const last = decisions.at(-1);
        return {
            decisions,
            ...(mapped.length > limit && last
                ? { nextCursor: encodePermissionDecisionCursor(last) }
                : {}),
        };
    }
    listActivePermissionDecisionsForPolicy() {
        return this.#db
            .prepare(permissionDecisionSelectSql("WHERE status = 'active'"))
            .all()
            .map(mapPermissionDecision);
    }
    revokePermissionDecision(input) {
        const existing = this.findPermissionDecision(input.id);
        if (!existing || existing.workspaceId !== input.workspaceId)
            return undefined;
        if (existing.status === "revoked")
            return existing;
        const now = new Date().toISOString();
        const result = this.#db
            .prepare(`UPDATE permission_decisions
         SET status = 'revoked', revoked_at = ?, revoke_audit_id = ?, revoke_reason = ?, revoke_source = ?, updated_at = ?
         WHERE id = ? AND workspace_id = ? AND status = 'active'`)
            .run(now, input.revokeAuditId, input.revokeReason ?? null, input.revokeSource ?? null, now, input.id, input.workspaceId);
        if ((result.changes ?? 0) < 1)
            return this.findPermissionDecision(input.id);
        const revoked = this.getPermissionDecision(input.id);
        if (isPermissionSessionDecisionActivity(revoked)) {
            this.#activity.appendPermissionDecisionActivityEvent(revoked, {
                kind: "session_decision_revoked",
                activityAt: now,
                status: "revoked",
                revokeReason: revoked.revokeReason,
                revokeSource: revoked.revokeSource,
            });
        }
        return revoked;
    }
    getPermissionDecision(id) {
        const decision = this.#db
            .prepare(permissionDecisionSelectSql("WHERE id = ?"))
            .get(id);
        return mapPermissionDecision(decision);
    }
}
