import { EncryptedContentSymbol, unixNow } from "applesauce-core/helpers";
import { CommentBlueprint } from "./blueprints/comment.js";
import { DeleteBlueprint } from "./blueprints/delete.js";
import { NoteBlueprint } from "./blueprints/note.js";
import { ReactionBlueprint } from "./blueprints/reaction.js";
import { NoteReplyBlueprint } from "./blueprints/reply.js";
import { ShareBlueprint } from "./blueprints/share.js";
import { eventPipe } from "./helpers/pipeline.js";
import { Client, includeReplaceableIdentifier, modifyTags, sign, stamp, stripSignature, stripStamp, stripSymbols, updateCreatedAt, } from "./operations/index.js";
/** Wraps a set of operations with common event operations */
function wrapCommon(...operations) {
    return eventPipe(
    // Remove all symbols from the event except for the encrypted content symbol
    stripSymbols([EncryptedContentSymbol]), 
    // Ensure all addressable evnets have "d" tags
    includeReplaceableIdentifier(), 
    // Apply operations
    ...operations, 
    // Include client tag if its set in the context
    (draft, ctx) => (ctx.client ? Client.setClient(ctx.client.name, ctx.client.address)(draft, ctx) : draft));
}
/** Creates an event using a template, context, and a set of operations */
export async function build(template, context, ...operations) {
    return await wrapCommon(stripSignature(), stripStamp(), ...operations)({ created_at: unixNow(), tags: [], content: "", ...template }, context);
}
/** Creates a blueprint function with operations */
export function blueprint(kind, ...operations) {
    return async (context) => await build({ kind }, context, ...operations);
}
export async function create(context, blueprint, ...args) {
    // Context, blueprint(context)
    if (arguments.length === 2) {
        return (await blueprint(context));
    }
    // Context, blueprintConstructor(...args)(context), ...args
    else {
        const constructor = blueprint;
        return await constructor(...args)(context);
    }
}
/** Modifies an event using a context and a set of operations */
export async function modify(event, context, ...operations) {
    return await wrapCommon(stripSignature(), stripStamp(), updateCreatedAt(), ...operations)(event, context);
}
export class EventFactory {
    context;
    constructor(context = {}) {
        this.context = context;
    }
    /** Build an event template with operations */
    async build(template, ...operations) {
        return await build(template, this.context, ...operations);
    }
    async create(blueprint, ...args) {
        // Context, blueprint(context)
        if (arguments.length === 1) {
            return (await blueprint(this.context));
        }
        // Context, blueprintConstructor(...args)(context), ...args
        else {
            const constructor = blueprint;
            return await constructor(...args)(this.context);
        }
    }
    /** Modify an existing event with operations and updated the created_at */
    async modify(draft, ...operations) {
        return await modify(draft, this.context, ...operations);
    }
    /** Modify a lists public and hidden tags and updated the created_at */
    async modifyTags(event, tagOperations, eventOperations) {
        let eventOperationsArr = [];
        // normalize event operation arg
        if (eventOperations === undefined)
            eventOperationsArr = [];
        else if (typeof eventOperations === "function")
            eventOperationsArr = [eventOperations];
        else if (Array.isArray(eventOperations))
            eventOperationsArr = eventOperations.filter((e) => !!e);
        // modify event
        return await this.modify(event, modifyTags(tagOperations), ...eventOperationsArr);
    }
    /** Attaches the signers pubkey to an event template */
    async stamp(draft) {
        return await stamp()(draft, this.context);
    }
    /** Signs a event template with the signer */
    async sign(draft) {
        return await sign()(draft, this.context);
    }
    // Helpers
    /** Sets the signer in the context */
    setSigner(signer) {
        this.context.signer = signer;
    }
    /** clears the signer in the context */
    clearSigner() {
        this.context.signer = undefined;
    }
    /** sets the client in the context */
    setClient(client) {
        this.context.client = client;
    }
    /** clears the client in the context */
    clearClient() {
        this.context.client = undefined;
    }
    /** Creates a short text note */
    note(...args) {
        return this.create(NoteBlueprint, ...args);
    }
    /** Create a NIP-22 comment */
    comment(...args) {
        return this.create(CommentBlueprint, ...args);
    }
    /** Creates a short text note reply */
    noteReply(...args) {
        return this.create(NoteReplyBlueprint, ...args);
    }
    /** Creates a reaction event */
    reaction(...args) {
        return this.create(ReactionBlueprint, ...args);
    }
    /** Creates a delete event */
    delete(...args) {
        return this.create(DeleteBlueprint, ...args);
    }
    /** Creates a share event */
    share(...args) {
        return this.create(ShareBlueprint, ...args);
    }
}
