/**
 * PageVersionService — append-only versioning of markdown pages (M17 Phase 4).
 * Parallel to VersionService but for filesystem pages. Each capture produces
 * one row in `page_version` with `release_id = NULL` (assigned by
 * `releaseService.createRelease`).
 */
import type Database from 'better-sqlite3';
import { PageSerializer, type PageSnapshotData } from './page-serializer.js';
export type PageChangedBy = 'user' | 'agent' | 'filesystem';
export type PageOp = 'create' | 'update' | 'delete';
/**
 * Dyskryminator źródła w `page_version`. `'page'` = pagesDir (M02), `'brief'` =
 * briefsDir (M21), `'patch'` = patchesDir (M23). Filtruje briefy/patche z
 * release snapshot/diff/restore — to artefakty POST-release, nie część
 * release'u (M17 spec, sekcja m17top001). Wersjonowanie jest niezależne per
 * `(path, kind)` — każda para ma własną oś czasu.
 */
export type PageKind = 'page' | 'brief' | 'patch';
export interface PageVersionListItem {
    id: number;
    path: string;
    version: number;
    op: PageOp;
    changedBy: PageChangedBy;
    releaseId: number | null;
    serializerVersion: string;
    createdAt: string;
    /** Human-readable opis zmiany. Null = brak (filesystem watcher, legacy). */
    changeSummary: string | null;
}
export interface PageVersionDetail extends PageVersionListItem {
    data: PageSnapshotData;
}
export declare class PageVersionService {
    private db;
    private serializer;
    constructor(db: Database.Database, serializer: PageSerializer);
    /**
     * Capture a new version of a page. For `op = 'delete'`, the caller must
     * provide the last-known content (since the file is gone) — used to build
     * a tombstone snapshot.
     *
     * M21 (m02multidir): caller can pass an alternative `serializer` so this
     * single shared `PageVersionService` can capture both `pagesDir` and
     * `briefsDir` files. Each `PageSerializer` is bound to a specific
     * `PagesService` (= rootDir) at construction time; the path-keyed
     * `page_version` table itself is rootDir-agnostic.
     */
    recordVersion(relPath: string, op: PageOp, changedBy: PageChangedBy, fallbackContent?: string, serializer?: PageSerializer, kind?: PageKind, changeSummary?: string | null): Promise<PageVersionListItem>;
    listVersions(relPath: string): PageVersionListItem[];
    getVersion(relPath: string, version: number): PageVersionDetail | null;
    /**
     * M17: latest captured version of a page at-or-before a given release.
     * Mirrors VersionService.getLatestVersionForEntity.
     */
    getLatestForPath(relPath: string, releaseId?: number | null, kind?: PageKind): PageVersionDetail | null;
    /** True when this path has any captured version. Used by initial-sync hook. */
    hasAny(relPath: string): boolean;
    /** Distinct paths captured at-or-before a given release (or all if undefined). */
    listPathsForRelease(releaseId: number): string[];
    /**
     * Count page captures with `release_id IS NULL` (waiting to be picked up by
     * next release). Excludes briefs — briefs nigdy nie wpadają do release'u
     * (M21 spec, sekcja m21db0001).
     */
    countUnreleased(): number;
    /**
     * Atomic: assign all unreleased page_version rows (kind='page') to a release.
     * Returns the count of rows updated. Briefy (kind='brief') NIGDY nie wpadają
     * do release'u — mają własną oś czasu, niezależną od release timeline.
     */
    assignToRelease(releaseId: number): number;
    /**
     * M23: numer wersji jest sekwencyjny per `(path, kind)`, nie per `path` —
     * page/brief/patch o tej samej ścieżce (teoretycznie) mają niezależne osie
     * czasu. W praktyce ścieżki nie kolidują, bo każdy `kind` ma własny katalog.
     */
    private nextVersionNumber;
    private synthesizeDeleteFromLastVersion;
    private toListItem;
    private toDetail;
}
