import { isRecord } from "../internal/rowMappers.js";
export class SyncStateRepository {
    #db;
    constructor(db) {
        this.#db = db;
    }
    recordSyncAttempt(input) {
        const now = new Date().toISOString();
        const existing = this.findSyncState(input.domain, input.idempotencyKey);
        if (existing &&
            (existing.workspaceId !== input.workspaceId ||
                existing.rowId !== input.rowId)) {
            throw new Error("sync-state-idempotency-binding-mismatch");
        }
        this.#db
            .prepare(`INSERT INTO sync_state (
          domain, idempotency_key, workspace_id, row_id,
          last_attempt_at, last_success_at, retry_count, last_failure_reason
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ON CONFLICT(domain, idempotency_key) DO UPDATE SET
          last_attempt_at = excluded.last_attempt_at,
          last_success_at = CASE WHEN excluded.last_success_at IS NOT NULL
                                 THEN excluded.last_success_at
                                 ELSE sync_state.last_success_at END,
          retry_count = CASE WHEN excluded.last_success_at IS NOT NULL
                             THEN 0
                             ELSE sync_state.retry_count + 1 END,
          last_failure_reason = excluded.last_failure_reason`)
            .run(input.domain, input.idempotencyKey, input.workspaceId, input.rowId, now, input.success ? now : null, input.success ? 0 : 1, input.success ? null : (input.failureReason ?? null));
    }
    findSyncState(domain, idempotencyKey) {
        const row = this.#db
            .prepare(`SELECT domain, idempotency_key, workspace_id, row_id,
                last_attempt_at, last_success_at, retry_count, last_failure_reason
         FROM sync_state WHERE domain = ? AND idempotency_key = ?`)
            .get(domain, idempotencyKey);
        if (!isRecord(row))
            return undefined;
        return {
            domain: String(row.domain),
            idempotencyKey: String(row.idempotency_key),
            workspaceId: String(row.workspace_id),
            rowId: String(row.row_id),
            lastAttemptAt: typeof row.last_attempt_at === "string" ? row.last_attempt_at : null,
            lastSuccessAt: typeof row.last_success_at === "string" ? row.last_success_at : null,
            retryCount: typeof row.retry_count === "number" ? row.retry_count : 0,
            lastFailureReason: typeof row.last_failure_reason === "string"
                ? row.last_failure_reason
                : null,
        };
    }
    listSyncStateForDomain(domain) {
        const rows = this.#db
            .prepare(`SELECT domain, idempotency_key, workspace_id, row_id,
                last_attempt_at, last_success_at, retry_count, last_failure_reason
         FROM sync_state WHERE domain = ?
         ORDER BY last_attempt_at DESC`)
            .all(domain);
        const out = [];
        for (const row of rows) {
            if (!isRecord(row))
                continue;
            out.push({
                domain: String(row.domain),
                idempotencyKey: String(row.idempotency_key),
                workspaceId: String(row.workspace_id),
                rowId: String(row.row_id),
                lastAttemptAt: typeof row.last_attempt_at === "string" ? row.last_attempt_at : null,
                lastSuccessAt: typeof row.last_success_at === "string" ? row.last_success_at : null,
                retryCount: typeof row.retry_count === "number" ? row.retry_count : 0,
                lastFailureReason: typeof row.last_failure_reason === "string"
                    ? row.last_failure_reason
                    : null,
            });
        }
        return out;
    }
}
