import type { AgentSettings } from "@lobu/core";
import type { RemoteAgent, RemoteAuthProfile, RemoteConnection, RemoteConnectorDefinition, RemoteEntityType, RemoteFeed, RemotePlatform, RemoteRelationshipType, RemoteWatcher } from "./client.js";
import type { DesiredAgent, DesiredAuthProfile, DesiredConnection, DesiredConnectorDefinition, DesiredEntityType, DesiredFeed, DesiredPlatform, DesiredRelationshipType, DesiredState, DesiredWatcher } from "./desired-state.js";
type DiffVerb = "create" | "update" | "noop" | "drift" | "delete";
interface BaseRow {
    verb: DiffVerb;
    /** Stable identifier for matching messages and UI. */
    id: string;
}
/**
 * The desired/remote/changed-fields triple shared by every per-resource row
 * kind. `changedFields` carries field-level changes when verb === "update".
 */
interface ResourceRow<D, R> extends BaseRow {
    desired?: D;
    remote?: R;
    changedFields?: string[];
}
export interface AgentDiffRow extends ResourceRow<DesiredAgent["metadata"], RemoteAgent> {
    kind: "agent";
}
export interface SettingsDiffRow extends BaseRow {
    kind: "settings";
    desired?: Partial<AgentSettings>;
    changedFields?: string[];
}
export interface PlatformDiffRow extends ResourceRow<DesiredPlatform, RemotePlatform> {
    kind: "platform";
    agentId: string;
    /** True when an update will restart the live worker — surfaced in the plan. */
    willRestart?: boolean;
}
export interface EntityTypeDiffRow extends ResourceRow<DesiredEntityType, RemoteEntityType> {
    kind: "entity-type";
}
export interface RelationshipTypeDiffRow extends ResourceRow<DesiredRelationshipType, RemoteRelationshipType> {
    kind: "relationship-type";
}
export interface WatcherDiffRow extends ResourceRow<DesiredWatcher, RemoteWatcher> {
    kind: "watcher";
    /**
     * Field names that require a `create_version` + `upgrade` (vs a plain
     * `update`). Apply uses this to route writes to the right admin action.
     */
    versionBoundFields?: string[];
    /**
     * True when the desired watcher declares a `reaction_script` — server stores
     * it write-only, so the diff can't tell whether it changed; apply always
     * re-pushes (idempotent). Matches the auth-profile credentials pattern.
     */
    reactionScriptDeclared?: boolean;
}
export interface ConnectorDefinitionDiffRow extends BaseRow {
    kind: "connector-definition";
    desired?: DesiredConnectorDefinition;
    /**
     * Whether the desired connector is currently installed remotely. When the
     * connector key isn't known up front (a local `.ts` the server hasn't
     * compiled), this is `false` and the verb is "create" — `install_connector`
     * is idempotent and reports `updated: false` on apply if nothing changed.
     */
    installedRemotely?: boolean;
}
export interface AuthProfileDiffRow extends ResourceRow<DesiredAuthProfile, RemoteAuthProfile> {
    kind: "auth-profile";
    /** True for `oauth_account` / `browser_session` profiles not yet `active`. */
    needsAuth?: boolean;
}
export interface ConnectionDiffRow extends ResourceRow<DesiredConnection, RemoteConnection> {
    kind: "connection";
}
export interface FeedDiffRow extends ResourceRow<DesiredFeed, RemoteFeed> {
    kind: "feed";
    /** Owning connection slug. */
    connectionSlug: string;
}
export type DiffRow = AgentDiffRow | SettingsDiffRow | PlatformDiffRow | EntityTypeDiffRow | RelationshipTypeDiffRow | WatcherDiffRow | ConnectorDefinitionDiffRow | AuthProfileDiffRow | ConnectionDiffRow | FeedDiffRow;
export interface DiffPlan {
    rows: DiffRow[];
    /** Aggregate counters for the summary line. */
    counts: {
        create: number;
        update: number;
        noop: number;
        drift: number;
        /**
         * Definitions absent from the config that apply will delete. Always 0
         * unless the config declares prune (`computeDiff({ prune: true })`);
         * otherwise those remote-only definitions are reported as `drift`.
         */
        delete: number;
    };
    /**
     * Informational, non-actionable notes — e.g. "connector X is installed
     * remotely but not declared locally". Rendered after the plan; never block
     * apply.
     */
    notes: string[];
}
export interface RemoteSnapshot {
    agents: RemoteAgent[];
    /** keyed by agentId */
    agentSettings: Map<string, AgentSettings | null>;
    /** keyed by agentId */
    platformsByAgent: Map<string, RemotePlatform[]>;
    entityTypes: RemoteEntityType[];
    relationshipTypes: RemoteRelationshipType[];
    watchers: RemoteWatcher[];
    connectorDefinitions: RemoteConnectorDefinition[];
    authProfiles: RemoteAuthProfile[];
    connections: RemoteConnection[];
    /** Feeds keyed by connection ID. */
    feedsByConnectionId: Map<number, RemoteFeed[]>;
}
/**
 * The subset of {@link DesiredState} the diff consumes — everything except the
 * apply-only knobs (prune flag, org metadata, requiredSecrets).
 */
type DesiredStateForDiff = Pick<DesiredState, "agents" | "memorySchema" | "watchers" | "connectors">;
interface ComputeDiffOptions {
    /** Limit the diff to a subset of resource kinds. */
    only?: "agents" | "memory";
    /**
     * When true, the config declares `prune: true`: it's the source of truth for
     * *definitions*, so a remote definition (entity type, relationship type,
     * watcher, connector definition) absent from desired is emitted as a `delete`
     * row instead of an ignored `drift` — INCLUDING definitions created via the
     * dashboard/API. Data (entity/relationship instances), connections, auth
     * profiles, feeds, agents, and platforms are never pruned. Default (false)
     * reports those remote-only definitions as `drift`.
     */
    prune?: boolean;
    /**
     * Target org id. The entity/relationship-type list endpoints also return
     * *public* definitions owned by OTHER orgs, which this org neither manages
     * nor can delete — so a remote type whose `organization_id` differs is
     * excluded from drift/delete entirely. Omit to disable the filter (tests).
     */
    orgId?: string;
}
export declare function computeDiff(desired: DesiredStateForDiff, remote: RemoteSnapshot, opts?: ComputeDiffOptions): DiffPlan;
export {};
//# sourceMappingURL=diff.d.ts.map