/**
 * This code was generated by
 * \ / _    _  _|   _  _
 *  | (_)\/(_)(_|\/| |(/_  v1.0.0
 *       /       /
 */

package com.twilio.rest.taskrouter.v1.workspace;

import com.twilio.base.Page;
import com.twilio.base.Reader;
import com.twilio.base.ResourceSet;
import com.twilio.converter.Promoter;
import com.twilio.exception.ApiConnectionException;
import com.twilio.exception.ApiException;
import com.twilio.exception.RestException;
import com.twilio.http.HttpMethod;
import com.twilio.http.Request;
import com.twilio.http.Response;
import com.twilio.http.TwilioRestClient;
import com.twilio.rest.Domains;

import java.util.List;

public class TaskReader extends Reader<Task> {
    private final String pathWorkspaceSid;
    private Integer priority;
    private List<String> assignmentStatus;
    private String workflowSid;
    private String workflowName;
    private String taskQueueSid;
    private String taskQueueName;
    private String evaluateTaskAttributes;
    private String ordering;
    private Boolean hasAddons;

    /**
     * Construct a new TaskReader.
     *
     * @param pathWorkspaceSid The SID of the Workspace with the Tasks to read
     */
    public TaskReader(final String pathWorkspaceSid) {
        this.pathWorkspaceSid = pathWorkspaceSid;
    }

    /**
     * The priority value of the Tasks to read. Returns the list of all Tasks in the
     * Workspace with the specified priority..
     *
     * @param priority The priority value of the Tasks to read
     * @return this
     */
    public TaskReader setPriority(final Integer priority) {
        this.priority = priority;
        return this;
    }

    /**
     * The `assignment_status` of the Tasks you want to read. Can be: `pending`,
     * `reserved`, `assigned`, `canceled`, `wrapping`, or `completed`. Returns all
     * Tasks in the Workspace with the specified `assignment_status`..
     *
     * @param assignmentStatus Returns the list of all Tasks in the Workspace with
     *                         the specified assignment_status
     * @return this
     */
    public TaskReader setAssignmentStatus(final List<String> assignmentStatus) {
        this.assignmentStatus = assignmentStatus;
        return this;
    }

    /**
     * The `assignment_status` of the Tasks you want to read. Can be: `pending`,
     * `reserved`, `assigned`, `canceled`, `wrapping`, or `completed`. Returns all
     * Tasks in the Workspace with the specified `assignment_status`..
     *
     * @param assignmentStatus Returns the list of all Tasks in the Workspace with
     *                         the specified assignment_status
     * @return this
     */
    public TaskReader setAssignmentStatus(final String assignmentStatus) {
        return setAssignmentStatus(Promoter.listOfOne(assignmentStatus));
    }

    /**
     * The SID of the Workflow with the Tasks to read. Returns the Tasks controlled
     * by the Workflow identified by this SID..
     *
     * @param workflowSid The SID of the Workflow with the Tasks to read
     * @return this
     */
    public TaskReader setWorkflowSid(final String workflowSid) {
        this.workflowSid = workflowSid;
        return this;
    }

    /**
     * The friendly name of the Workflow with the Tasks to read. Returns the Tasks
     * controlled by the Workflow identified by this friendly name..
     *
     * @param workflowName The friendly name of the Workflow with the Tasks to read
     * @return this
     */
    public TaskReader setWorkflowName(final String workflowName) {
        this.workflowName = workflowName;
        return this;
    }

    /**
     * The SID of the TaskQueue with the Tasks to read. Returns the Tasks waiting in
     * the TaskQueue identified by this SID..
     *
     * @param taskQueueSid The SID of the TaskQueue with the Tasks to read
     * @return this
     */
    public TaskReader setTaskQueueSid(final String taskQueueSid) {
        this.taskQueueSid = taskQueueSid;
        return this;
    }

    /**
     * The `friendly_name` of the TaskQueue with the Tasks to read. Returns the
     * Tasks waiting in the TaskQueue identified by this friendly name..
     *
     * @param taskQueueName The friendly_name of the TaskQueue with the Tasks to
     *                      read
     * @return this
     */
    public TaskReader setTaskQueueName(final String taskQueueName) {
        this.taskQueueName = taskQueueName;
        return this;
    }

    /**
     * The attributes of the Tasks to read. Returns the Tasks that match the
     * attributes specified in this parameter..
     *
     * @param evaluateTaskAttributes The task attributes of the Tasks to read
     * @return this
     */
    public TaskReader setEvaluateTaskAttributes(final String evaluateTaskAttributes) {
        this.evaluateTaskAttributes = evaluateTaskAttributes;
        return this;
    }

    /**
     * How to order the returned Task resources. y default, Tasks are sorted by
     * ascending DateCreated. This value is specified as: `Attribute:Order`, where
     * `Attribute` can be either `Priority` or `DateCreated` and `Order` can be
     * either `asc` or `desc`. For example, `Priority:desc` returns Tasks ordered in
     * descending order of their Priority. Multiple sort orders can be specified in
     * a comma-separated list such as `Priority:desc,DateCreated:asc`, which returns
     * the Tasks in descending Priority order and ascending DateCreated Order..
     *
     * @param ordering Controls the order of the Tasks returned
     * @return this
     */
    public TaskReader setOrdering(final String ordering) {
        this.ordering = ordering;
        return this;
    }

    /**
     * Whether to read Tasks with addons. If `true`, returns only Tasks with addons.
     * If `false`, returns only Tasks without addons..
     *
     * @param hasAddons Whether to read Tasks with addons
     * @return this
     */
    public TaskReader setHasAddons(final Boolean hasAddons) {
        this.hasAddons = hasAddons;
        return this;
    }

    /**
     * Make the request to the Twilio API to perform the read.
     *
     * @param client TwilioRestClient with which to make the request
     * @return Task ResourceSet
     */
    @Override
    public ResourceSet<Task> read(final TwilioRestClient client) {
        return new ResourceSet<>(this, client, firstPage(client));
    }

    /**
     * Make the request to the Twilio API to perform the read.
     *
     * @param client TwilioRestClient with which to make the request
     * @return Task ResourceSet
     */
    @Override
    @SuppressWarnings("checkstyle:linelength")
    public Page<Task> firstPage(final TwilioRestClient client) {
        Request request = new Request(
            HttpMethod.GET,
            Domains.TASKROUTER.toString(),
            "/v1/Workspaces/" + this.pathWorkspaceSid + "/Tasks"
        );

        addQueryParams(request);
        return pageForRequest(client, request);
    }

    /**
     * Retrieve the target page from the Twilio API.
     *
     * @param targetUrl API-generated URL for the requested results page
     * @param client TwilioRestClient with which to make the request
     * @return Task ResourceSet
     */
    @Override
    @SuppressWarnings("checkstyle:linelength")
    public Page<Task> getPage(final String targetUrl, final TwilioRestClient client) {
        Request request = new Request(
            HttpMethod.GET,
            targetUrl
        );

        return pageForRequest(client, request);
    }

    /**
     * Retrieve the next page from the Twilio API.
     *
     * @param page current page
     * @param client TwilioRestClient with which to make the request
     * @return Next Page
     */
    @Override
    public Page<Task> nextPage(final Page<Task> page,
                               final TwilioRestClient client) {
        Request request = new Request(
            HttpMethod.GET,
            page.getNextPageUrl(Domains.TASKROUTER.toString())
        );
        return pageForRequest(client, request);
    }

    /**
     * Retrieve the previous page from the Twilio API.
     *
     * @param page current page
     * @param client TwilioRestClient with which to make the request
     * @return Previous Page
     */
    @Override
    public Page<Task> previousPage(final Page<Task> page,
                                   final TwilioRestClient client) {
        Request request = new Request(
            HttpMethod.GET,
            page.getPreviousPageUrl(Domains.TASKROUTER.toString())
        );
        return pageForRequest(client, request);
    }

    /**
     * Generate a Page of Task Resources for a given request.
     *
     * @param client TwilioRestClient with which to make the request
     * @param request Request to generate a page for
     * @return Page for the Request
     */
    private Page<Task> pageForRequest(final TwilioRestClient client, final Request request) {
        Response response = client.request(request);

        if (response == null) {
            throw new ApiConnectionException("Task read failed: Unable to connect to server");
        } else if (!TwilioRestClient.SUCCESS.test(response.getStatusCode())) {
            RestException restException = RestException.fromJson(response.getStream(), client.getObjectMapper());
            if (restException == null) {
                throw new ApiException("Server Error, no content");
            }
           throw new ApiException(restException);
        }

        return Page.fromJson(
            "tasks",
            response.getContent(),
            Task.class,
            client.getObjectMapper()
        );
    }

    /**
     * Add the requested query string arguments to the Request.
     *
     * @param request Request to add query string arguments to
     */
    private void addQueryParams(final Request request) {
        if (priority != null) {
            request.addQueryParam("Priority", priority.toString());
        }

        if (assignmentStatus != null) {
            for (String prop : assignmentStatus) {
                request.addQueryParam("AssignmentStatus", prop);
            }
        }

        if (workflowSid != null) {
            request.addQueryParam("WorkflowSid", workflowSid);
        }

        if (workflowName != null) {
            request.addQueryParam("WorkflowName", workflowName);
        }

        if (taskQueueSid != null) {
            request.addQueryParam("TaskQueueSid", taskQueueSid);
        }

        if (taskQueueName != null) {
            request.addQueryParam("TaskQueueName", taskQueueName);
        }

        if (evaluateTaskAttributes != null) {
            request.addQueryParam("EvaluateTaskAttributes", evaluateTaskAttributes);
        }

        if (ordering != null) {
            request.addQueryParam("Ordering", ordering);
        }

        if (hasAddons != null) {
            request.addQueryParam("HasAddons", hasAddons.toString());
        }

        if (getPageSize() != null) {
            request.addQueryParam("PageSize", Integer.toString(getPageSize()));
        }
    }
}