import type { Address } from '../Address';
import { DID } from '../DID';
import type { Expression } from '../expression/Expression';
import { Perspective, PerspectiveExpression } from '../perspectives/Perspective';
import { PerspectiveDiff } from '../perspectives/PerspectiveDiff';
import { PerspectiveState } from '../perspectives/PerspectiveHandle';
/** Interface of AD4M Languages
 *
 * Any JavaScript module that implements a create() function that returns an object that implements this interface
 * is a valid AD4M language.
 * So the AD4M-internal representation of a language is an object that implements this interface.
 *
 * Since there are a few different kinds of languages, this interface is split into optional sub-interfaces.
 * The only required property is the name of the language.
 *
 * The most usual kind of language is the "Expression Language", which is a language that can be used to create
 * and share Expressions.
 * For that, implement the expressionsAdapter and expressionUI interface.
 *
 * The second most common kind of language is the "Link Language", which is a language that builds the core
 * of AD4M Neighbourhoods.
 * For that, implement the linksAdapter interface.
 */
export interface Language {
    readonly name: string;
    /** Flagging expressions as immutable to enable
     * expression caching in the ad4m-executor
     */
    isImmutableExpression?(expression: Address): boolean;
    /** ExpressionAdapter implements means of getting an Expression
     * by address and putting an expression
     */
    readonly expressionAdapter?: ExpressionAdapter;
    /** Interface for getting UI/web components for rendering Expressions of this Language */
    readonly expressionUI?: ExpressionUI;
    /** Interface of LinkLanguages for the core implementation of Neighbourhoods */
    readonly linksAdapter?: LinkSyncAdapter;
    /** Additional Interface of LinkLanguages that support telepresence features,
     * that is:
     *  - seeing who is online and getting a status
     *  - sending/receiveing p2p signals to other online agents without affecting
     *    the shared Perspective of the Neighbourhood
     *  (see TelepresenceAdapter for more details)
    */
    readonly telepresenceAdapter?: TelepresenceAdapter;
    /** Implementation of a Language that defines and stores Languages*/
    readonly languageAdapter?: LanguageAdapter;
    /** Optional adapter for getting Expressions by author */
    readonly getByAuthorAdapter?: GetByAuthorAdapter;
    /** Optional adapter for getting all Expressions */
    readonly getAllAdapter?: GetAllAdapter;
    /** Optional adapter for direct messaging between agents */
    readonly directMessageAdapter?: DirectMessageAdapter;
    /** Interface for providing UI components for the settings of this Language */
    readonly settingsUI?: SettingsUI;
    /** Optional function to make any cleanup/teardown if your language gets deleting in the ad4m-executor */
    readonly teardown?: () => void;
    /** All available interactions this agent could execute on given expression */
    interactions(expression: Address): Interaction[];
}
/** UI factories returning web components */
export interface ExpressionUI {
    /** Returns JS code of a web component that renders the given expression */
    icon(): string;
    /** Returns JS code of a web component used to create new expressions */
    constructorIcon(): string;
}
export interface SettingsUI {
    settingsIcon(): string;
}
/** Interface for the most common Expression Languages */
export interface ExpressionAdapter {
    /** Returns an Expression by address, or null if there is no Expression
     * with that given address
     */
    get(address: Address): Promise<Expression | null>;
    /** Strategy for putting an expression with needs to be different
     * for those two cases:
     * 1. PublicSharing means that this language supports the creation
     *    and sharing of Expressions, which is the common use-case
     * 2. ReadOnlyLanguage means that the Language implements a pre-defined
     *    set of expressions (which can be infinite or finite).
     *    For example the url-iframe Language which directly maps URLs to
     *    addresses - meaning every well formed URL is an address in this
     *    Language. Or a potential Language implementing the verbs/predicates
     *    of a spec like FOAF.
     */
    putAdapter: PublicSharing | ReadOnlyLanguage;
}
/** Implement this interface if your Language supports creation of sharing
 * of Expressions.
 * See ExpressionAdapter
 */
export interface PublicSharing {
    /** Create an Expression and shares it.
     * Return the Expression's address.
     * @param content is the object created by the constructorIcon component
     */
    createPublic(content: object): Promise<Address>;
}
/** Implement this interface if your Language is defined over a static
 * set of pre-defined Expressions.
 */
export interface ReadOnlyLanguage {
    /** This just calculates the address of an object
     * @param content is the object created by the constructorIcon component
     */
    addressOf(content: object): Promise<Address>;
}
export interface LanguageAdapter {
    getLanguageSource(address: Address): Promise<string>;
}
export interface GetByAuthorAdapter {
    getByAuthor(author: DID, count: number, page: number): Promise<Expression[] | null>;
}
export interface GetAllAdapter {
    getAll(filter: any, count: number, page: number): Promise<Expression[] | null>;
}
export type PerspectiveDiffObserver = (diff: PerspectiveDiff) => void;
export type SyncStateChangeObserver = (state: PerspectiveState) => void;
/** Interface for "Link Languages" that facilitate the synchronization
 * between agents' local Perspectives inside a Neighbourhood.
 * The assumption is that every version of the shared Perspective
 * is labeled with a unique revision string.
 * Changes are committed and retrieved through diffs.
 * Think of a LinkSyncAdapter as a git branch to which agents commit
 * their changes to and pull diffs from their current revision
 * to the latest one.
 */
export interface LinkSyncAdapter {
    writable(): boolean;
    public(): boolean;
    others(): Promise<DID[]>;
    /** What revision are we on now -> what changes are included in output of render() */
    currentRevision(): Promise<string>;
    /**
     * Check for and get new changes,
     * notify others of local changes.
     * This function will be called every
     * few seconds by the ad4m-executor.
     *  */
    sync(): Promise<PerspectiveDiff>;
    /** Returns the full, rendered Perspective at currentRevision */
    render(): Promise<Perspective>;
    /** Publish changes */
    commit(diff: PerspectiveDiff): Promise<string>;
    /** Get push notification when a diff got published */
    addCallback(callback: PerspectiveDiffObserver): any;
    /** Add a sync state callback method */
    addSyncStateChangeCallback(callback: SyncStateChangeObserver): any;
}
export type MessageCallback = (message: PerspectiveExpression) => void;
export type StatusCallback = (caller: DID) => Perspective;
export interface DirectMessageAdapter {
    recipient(): DID;
    status(): Promise<PerspectiveExpression | void>;
    sendP2P(message: Perspective): Promise<PerspectiveExpression | void>;
    sendInbox(message: Perspective): Promise<PerspectiveExpression | void>;
    setStatus(status: PerspectiveExpression): any;
    inbox(filter?: string): Promise<PerspectiveExpression[]>;
    addMessageCallback(callback: MessageCallback): any;
}
export declare class InteractionParameter {
    name: string;
    type: string;
}
export declare class InteractionMeta {
    label: string;
    name: string;
    parameters: InteractionParameter[];
}
export interface Interaction {
    readonly label: string;
    readonly name: string;
    readonly parameters: InteractionParameter[];
    execute(parameters: object): Promise<string | null>;
}
export declare class InteractionCall {
    name: string;
    parametersStringified: string;
    get parameters(): object;
    constructor(name: string, parameters: object);
}
export declare class OnlineAgent {
    did: DID;
    status: PerspectiveExpression;
}
export type TelepresenceSignalCallback = (payload: PerspectiveExpression) => void;
export interface TelepresenceAdapter {
    setOnlineStatus(status: PerspectiveExpression): Promise<void>;
    getOnlineAgents(): Promise<OnlineAgent[]>;
    sendSignal(remoteAgentDid: string, payload: PerspectiveExpression): Promise<object>;
    sendBroadcast(payload: PerspectiveExpression): Promise<object>;
    registerSignalCallback(callback: TelepresenceSignalCallback): Promise<void>;
}
