/*
 * Copyright 2022 Conductor Authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.netflix.conductor.service;

import java.util.List;
import java.util.Map;

import org.springframework.validation.annotation.Validated;

import com.netflix.conductor.common.metadata.tasks.PollData;
import com.netflix.conductor.common.metadata.tasks.Task;
import com.netflix.conductor.common.metadata.tasks.TaskExecLog;
import com.netflix.conductor.common.metadata.tasks.TaskResult;
import com.netflix.conductor.common.run.ExternalStorageLocation;
import com.netflix.conductor.common.run.SearchResult;
import com.netflix.conductor.common.run.TaskSummary;
import com.netflix.conductor.model.TaskModel;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;

@Validated
public interface TaskService {

    /**
     * Poll for a task of a certain type.
     *
     * @param taskType Task name
     * @param workerId Id of the workflow
     * @param domain Domain of the workflow
     * @return polled {@link Task}
     */
    Task poll(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType,
            String workerId,
            String domain);

    /**
     * Batch Poll for a task of a certain type.
     *
     * @param taskType Task Name
     * @param workerId Id of the workflow
     * @param domain Domain of the workflow
     * @param count Number of tasks
     * @param timeout Timeout for polling in milliseconds
     * @return list of {@link Task}
     */
    List<Task> batchPoll(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType,
            String workerId,
            String domain,
            Integer count,
            Integer timeout);

    /**
     * Get in progress tasks. The results are paginated.
     *
     * @param taskType Task Name
     * @param startKey Start index of pagination
     * @param count Number of entries
     * @return list of {@link Task}
     */
    List<Task> getTasks(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType,
            String startKey,
            Integer count);

    /**
     * Get in progress task for a given workflow id.
     *
     * @param workflowId Id of the workflow
     * @param taskReferenceName Task reference name.
     * @return instance of {@link Task}
     */
    Task getPendingTaskForWorkflow(
            @NotEmpty(message = "WorkflowId cannot be null or empty.") String workflowId,
            @NotEmpty(message = "TaskReferenceName cannot be null or empty.")
                    String taskReferenceName);

    /**
     * Updates a task.
     *
     * @param taskResult Instance of {@link TaskResult}
     * @return the updated task.
     */
    TaskModel updateTask(
            @NotNull(message = "TaskResult cannot be null or empty.") @Valid TaskResult taskResult);

    /**
     * Ack Task is received.
     *
     * @param taskId Id of the task
     * @param workerId Id of the worker
     * @return `true|false` if task if received or not
     */
    String ackTaskReceived(
            @NotEmpty(message = "TaskId cannot be null or empty.") String taskId, String workerId);

    /**
     * Ack Task is received.
     *
     * @param taskId Id of the task
     * @return `true|false` if task if received or not
     */
    boolean ackTaskReceived(@NotEmpty(message = "TaskId cannot be null or empty.") String taskId);

    /**
     * Log Task Execution Details.
     *
     * @param taskId Id of the task
     * @param log Details you want to log
     */
    void log(@NotEmpty(message = "TaskId cannot be null or empty.") String taskId, String log);

    /**
     * Get Task Execution Logs.
     *
     * @param taskId Id of the task.
     * @return list of {@link TaskExecLog}
     */
    List<TaskExecLog> getTaskLogs(
            @NotEmpty(message = "TaskId cannot be null or empty.") String taskId);

    /**
     * Get task by Id.
     *
     * @param taskId Id of the task.
     * @return instance of {@link Task}
     */
    Task getTask(@NotEmpty(message = "TaskId cannot be null or empty.") String taskId);

    /**
     * Remove Task from a Task type queue.
     *
     * @param taskType Task Name
     * @param taskId ID of the task
     */
    void removeTaskFromQueue(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType,
            @NotEmpty(message = "TaskId cannot be null or empty.") String taskId);

    /**
     * Remove Task from a Task type queue.
     *
     * @param taskId ID of the task
     */
    void removeTaskFromQueue(@NotEmpty(message = "TaskId cannot be null or empty.") String taskId);

    /**
     * Get Task type queue sizes.
     *
     * @param taskTypes List of task types.
     * @return map of task type as Key and queue size as value.
     */
    Map<String, Integer> getTaskQueueSizes(List<String> taskTypes);

    /**
     * Get the queue size for a Task Type. The input can optionally include <code>domain</code>,
     * <code>isolationGroupId</code> and <code>executionNamespace</code>.
     *
     * @return
     */
    Integer getTaskQueueSize(
            String taskType, String domain, String isolationGroupId, String executionNamespace);

    /**
     * Get the details about each queue.
     *
     * @return map of queue details.
     */
    Map<String, Map<String, Map<String, Long>>> allVerbose();

    /**
     * Get the details about each queue.
     *
     * @return map of details about each queue.
     */
    Map<String, Long> getAllQueueDetails();

    /**
     * Get the last poll data for a given task type.
     *
     * @param taskType Task Name
     * @return list of {@link PollData}
     */
    List<PollData> getPollData(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType);

    /**
     * Get the last poll data for all task types.
     *
     * @return list of {@link PollData}
     */
    List<PollData> getAllPollData();

    /**
     * Requeue pending tasks.
     *
     * @param taskType Task name.
     * @return number of tasks requeued.
     */
    String requeuePendingTask(
            @NotEmpty(message = "TaskType cannot be null or empty.") String taskType);

    /**
     * Search for tasks based in payload and other parameters. Use sort options as ASC or DESC e.g.
     * sort=name or sort=workflowId. If order is not specified, defaults to ASC.
     *
     * @param start Start index of pagination
     * @param size Number of entries
     * @param sort Sorting type ASC|DESC
     * @param freeText Text you want to search
     * @param query Query you want to search
     * @return instance of {@link SearchResult}
     */
    SearchResult<TaskSummary> search(
            int start, int size, String sort, String freeText, String query);

    /**
     * Search for tasks based in payload and other parameters. Use sort options as ASC or DESC e.g.
     * sort=name or sort=workflowId. If order is not specified, defaults to ASC.
     *
     * @param start Start index of pagination
     * @param size Number of entries
     * @param sort Sorting type ASC|DESC
     * @param freeText Text you want to search
     * @param query Query you want to search
     * @return instance of {@link SearchResult}
     */
    SearchResult<Task> searchV2(int start, int size, String sort, String freeText, String query);

    /**
     * Get the external storage location where the task output payload is stored/to be stored
     *
     * @param path the path for which the external storage location is to be populated
     * @param operation the operation to be performed (read or write)
     * @param payloadType the type of payload (input or output)
     * @return {@link ExternalStorageLocation} containing the uri and the path to the payload is
     *     stored in external storage
     */
    ExternalStorageLocation getExternalStorageLocation(
            String path, String operation, String payloadType);

    String updateTask(
            String workflowId,
            String taskRefName,
            TaskResult.Status status,
            String workerId,
            Map<String, Object> output);
}
