package com.google.ai.edge.localagents.rag.memory;

import com.google.ai.edge.localagents.rag.models.EmbedData;
import com.google.ai.edge.localagents.rag.models.Embedder;
import com.google.ai.edge.localagents.rag.models.EmbeddingRequest;
import com.google.ai.edge.localagents.rag.models.EmbedData.TaskType;
import com.google.ai.edge.localagents.rag.retrieval.RetrievalEntity;
import com.google.ai.edge.localagents.rag.retrieval.RetrievalRequest;
import com.google.ai.edge.localagents.rag.retrieval.RetrievalResponse;
import com.google.ai.edge.localagents.rag.retrieval.SemanticDataEntry;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public final class DefaultSemanticTextMemory implements SemanticMemory<String> {
    private final VectorStore<String> vectorStore;
    private final Embedder<String> embeddingModel;
    private final Executor workerExecutor;

    public DefaultSemanticTextMemory(VectorStore<String> vectorStore, Embedder<String> embeddingModel) {
        this.vectorStore = vectorStore;
        this.embeddingModel = embeddingModel;
        this.workerExecutor = Executors.newSingleThreadExecutor((new ThreadFactoryBuilder()).setNameFormat("default-semantic-text-memory-pool-%d").setPriority(5).build());
    }

    public ListenableFuture<RetrievalResponse<String>> retrieveResults(RetrievalRequest<String> request) {
        EmbedData.Builder<String> embedDataBuilder = EmbedData.builder().setData((String)request.getQuery());
        switch (request.getConfig().getTask()) {
            case TASK_UNSPECIFIED:
            case RETRIEVAL_QUERY:
                embedDataBuilder.setTask(TaskType.RETRIEVAL_QUERY);
                break;
            case QUESTION_ANSWERING:
                embedDataBuilder.setTask(TaskType.QUESTION_ANSWERING);
        }

        EmbeddingRequest<String> embeddingRequest = EmbeddingRequest.create(ImmutableList.of(embedDataBuilder.build()));
        return Futures.transform(this.embeddingModel.getEmbeddings(embeddingRequest), (embeddings) -> {
            List<VectorStoreRecord<String>> records = this.vectorStore.getNearestRecords(embeddings, request.getConfig().getTopK(), request.getConfig().getMinSimilarityScore());
            ImmutableList<RetrievalEntity<String>> entities = (ImmutableList)records.stream().map((record) -> RetrievalEntity.builder().setData((String)record.getData()).setEmbeddings(record.getEmbeddings()).setMetadata(record.getMetadata()).build()).collect(ImmutableList.toImmutableList());
            return RetrievalResponse.create(entities);
        }, this.workerExecutor);
    }

    public ListenableFuture<Boolean> recordMemoryItem(String text) {
        SemanticDataEntry<String> dataEntry = SemanticDataEntry.create(text);
        return this.recordMemoryEntry(dataEntry);
    }

    public ListenableFuture<Boolean> recordMemoryEntry(SemanticDataEntry<String> dataEntry) {
        EmbedData<String> embedText = EmbedData.builder().setData((String)dataEntry.getCustomEmbeddingData().orElse((String)dataEntry.getData())).setTask(TaskType.RETRIEVAL_DOCUMENT).build();
        EmbeddingRequest<String> embeddingRequest = EmbeddingRequest.create(ImmutableList.of(embedText));
        return Futures.transform(this.embeddingModel.getEmbeddings(embeddingRequest), (embeddings) -> {
            VectorStoreRecord<String> record = VectorStoreRecord.builder().setData((String)dataEntry.getData()).setEmbeddings(embeddings).setMetadata(dataEntry.getMetadata()).build();
            this.vectorStore.insert(record);
            return true;
        }, this.workerExecutor);
    }

    public ListenableFuture<Boolean> recordBatchedMemoryItems(ImmutableList<String> texts) {
        return this.recordBatchedMemoryEntries((ImmutableList)texts.stream().map(SemanticDataEntry::create).collect(ImmutableList.toImmutableList()));
    }

    public ListenableFuture<Boolean> recordBatchedMemoryEntries(ImmutableList<SemanticDataEntry<String>> dataEntries) {
        if (dataEntries.isEmpty()) {
            return Futures.immediateFuture(false);
        } else {
            ImmutableList<EmbedData<String>> entries = (ImmutableList)dataEntries.stream().map((dataEntry) -> EmbedData.builder().setData((String)dataEntry.getCustomEmbeddingData().orElse((String)dataEntry.getData())).setTask(TaskType.RETRIEVAL_DOCUMENT).build()).collect(ImmutableList.toImmutableList());
            EmbeddingRequest<String> request = EmbeddingRequest.create(entries);
            return Futures.transform(this.embeddingModel.getBatchEmbeddings(request), (embeddingsList) -> {
                if (embeddingsList.size() != dataEntries.size()) {
                    throw new AssertionError(String.format("Embeddings list size is not equal to memory entries size, %d != %d", embeddingsList.size(), dataEntries.size()));
                } else {
                    for(int i = 0; i < embeddingsList.size(); ++i) {
                        VectorStoreRecord<String> record = VectorStoreRecord.builder().setData((String)((SemanticDataEntry)dataEntries.get(i)).getData()).setEmbeddings((ImmutableList)embeddingsList.get(i)).setMetadata(((SemanticDataEntry)dataEntries.get(i)).getMetadata()).build();
                        this.vectorStore.insert(record);
                    }

                    return true;
                }
            }, this.workerExecutor);
        }
    }
}
out task is to calculate the embedding time using this source code tell me how can we calculate the time it's taking to embedd and retrive the embedding indentify the functions responsible for that and tell me