import { FactorsType, ScalarType, PairByKeyType, CandidateType, RowType, OptionsType, PairType, SuggestRowType } from "./types";
import { UncoveredPair } from "./exceptions";
export declare class Row extends Map<ScalarType, number> implements RowType {
    /** Pair keys that failed constraint checks for this row attempt. */
    invalidPairs: Set<ScalarType>;
    constructor(row: CandidateType);
    getPairKey(...newPair: number[]): ScalarType;
    copy(row: Row): void;
}
export interface ControllerStats {
    /** Total pairs before any pruning. */
    totalPairs: number;
    /** Number of pairs pruned by constraints (infeasible). */
    prunedPairs: number;
    /** Number of pairs consumed so far. */
    coveredPairs: number;
    /** Coverage ratio: coveredPairs / (totalPairs - prunedPairs). */
    progress: number;
    /** Number of generated rows. */
    rowCount: number;
    /** Pairs that could not be covered. Populated after make/makeAsync completes. */
    uncoveredPairs: UncoveredPair[];
    /** Counts of values filled by close() (completion), keyed by factor then value. */
    completions: Record<string, Record<string, number>>;
}
export declare class Controller<T extends FactorsType> {
    factors: FactorsType;
    options: OptionsType<T>;
    factorLength: number;
    factorIsArray: Boolean;
    private serials;
    private parents;
    private indices;
    incomplete: PairByKeyType;
    private rejected;
    row: Row;
    private _totalPairs;
    private _prunedPairs;
    private _rowCount;
    private _uncoveredPairs;
    private _completions;
    get stats(): ControllerStats;
    private constraints;
    private constraintsByKey;
    private comparer;
    /**
     * Indices into `constraints` that have already evaluated to `true`
     * against the **current** row. Cleared whenever the row is reset or
     * yielded. Safe because the row only grows and each condition is
     * deterministic over its declared keys.
     */
    private passedIndexes;
    constructor(factors: FactorsType, options?: OptionsType<T>);
    /** Normalize `in` conditions: convert `values` arrays to Sets for O(1) lookup. */
    private static normalizeCondition;
    private resolveConstraints;
    private serialize;
    private setIncomplete;
    /**
     * Try to add a candidate pair to the current row. Evaluates constraints
     * against a snapshot (row + pair) without mutating `this.row`. If all
     * constraints pass (or are unknown), the pair is committed to `this.row`
     * and `true` is returned. If any constraint definitively fails, `this.row`
     * is unchanged and `false` is returned.
     */
    private setPair;
    private consumePairs;
    getCandidate(pair: PairType): CandidateType;
    isCompatible(pair: PairType): number | null;
    /**
     * Check whether adding `candidate` to `row` would violate any constraint.
     * Returns `true` (OK), `false` (definitively violated), or `null`
     * (some dependency is still missing — defer).
     *
     * Constraints already in `passedIndexes` are skipped.
     */
    private storableCheck;
    /**
     * Returns the number of new keys this candidate would add to `row`, or
     * `null` if the candidate is incompatible or would definitively violate a
     * constraint. `null` results from three-valued evaluation are treated
     * as "OK for now" — they will be rechecked once more keys are known.
     */
    storable(candidate: CandidateType, row?: Row): number | null;
    /**
     * Evaluate constraints against `row` and mark those that pass as done.
     * Returns `false` if any constraint definitively fails (= the row is
     * unsalvageable and should be abandoned), `true` otherwise.
     */
    private markPassedConstraints;
    /**
     * Forward checking: given a snapshot row, propagate constraints to prune
     * domains of unfilled factors. If any factor's domain becomes empty, the
     * current assignment is unsolvable — return false.
     *
     * This is read-only: it does NOT modify this.row. It builds a temporary
     * domain map and iteratively narrows it by evaluating constraints with
     * each candidate value.
     */
    private forwardCheck;
    isFilled(row: Row): boolean;
    private toMap;
    private toObject;
    private reset;
    private restore;
    /**
     * Fill the remaining unfilled factors of `this.row` and check constraints.
     * Uses depth-first backtracking: each unfilled factor tries its values in
     * order (weight-sorted on the first pass). When a value causes a
     * constraint to evaluate to `false` (via three-valued `storable`), the
     * next candidate is tried; if all candidates are exhausted, the previous
     * factor is backtracked.
     *
     * Returns `true` when a valid completion is found (the row is updated in
     * place), or `false` when no valid completion exists.
     */
    /**
     * Result of close(): `true` = valid completion found; `false` = failed;
     * or an object with the conflict keys from the first failing constraint.
     */
    private close;
    get strength(): number;
    get allStrengths(): number[];
    private valueToSerial;
    private applyPreset;
    private orderByWeight;
    get isComplete(): boolean;
    /**
     * Find the keys of the first failing constraint on the current row.
     * Returns the set of factor keys that participate in the conflict,
     * or null if the row passes all constraints.
     */
    private findConflictKeys;
    /**
     * Analyse remaining incomplete pairs and identify which constraint(s)
     * make each pair infeasible. Used to build a diagnostic when throwing
     * NeverMatch.
     */
    private diagnoseUncoveredPairs;
    /**
     * Record which factor values were filled by close() (completion) rather
     * than by greedy. `greedyKeys` are the keys that were already in the row
     * before close() ran.
     */
    private recordCompletions;
    get progress(): number;
    make<T extends FactorsType>(): SuggestRowType<T>[];
    makeAsync<T extends FactorsType>(): Generator<SuggestRowType<T>, void, unknown>;
}
