package org.ghidra.bridge.edit;

import ghidra.program.model.listing.CommentType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import org.ghidra.bridge.query.ProgramModel;
import org.ghidra.bridge.session.ProgramHandle;
import org.ghidra.bridge.session.TransactionHandle;

public final class ProgramEdits {
    private ProgramEdits() {
    }

    public static TransactionHandle startTransaction(ProgramHandle programHandle, String description) {
        Program program = programHandle.program();
        return new TransactionHandle(program, program.startTransaction(description));
    }

    public static void endTransaction(TransactionHandle transactionHandle, boolean commit) {
        Program program = transactionHandle.program();
        program.endTransaction(transactionHandle.transactionId(), true);
        if (commit) {
            return;
        }

        int rollbackTransactionId =
            program.startTransaction("rollback " + transactionHandle.transactionId());
        try {
            // Rollback edits define the Rust-facing rollback contract for exposed mutators.
            transactionHandle.rollbackEdits();
        } finally {
            program.endTransaction(rollbackTransactionId, true);
        }
    }

    public static void setFunctionPlateComment(
        TransactionHandle transactionHandle,
        String functionAddress,
        String comment
    ) {
        Function function = ProgramModel.requireFunctionAt(transactionHandle.program(), functionAddress);
        String originalComment = transactionHandle.program()
            .getListing()
            .getComment(CommentType.PLATE, function.getEntryPoint());
        transactionHandle.addRollbackEdit(() -> transactionHandle.program().getListing().setComment(
            function.getEntryPoint(),
            CommentType.PLATE,
            originalComment
        ));
        transactionHandle.program().getListing().setComment(
            function.getEntryPoint(),
            CommentType.PLATE,
            comment
        );
    }

    public static String functionPlateComment(ProgramHandle programHandle, String functionAddress) {
        Function function = ProgramModel.requireFunctionAt(programHandle.program(), functionAddress);
        return programHandle.program()
            .getListing()
            .getComment(CommentType.PLATE, function.getEntryPoint());
    }
}
