// Package edgeapi provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/ashb/oapi-resty-codegen version v0.0.0-20250930162853-bec2fc27e468 DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// 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 edgeapi

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/oapi-codegen/runtime"
	openapi_types "github.com/oapi-codegen/runtime/types"
	"resty.dev/v3"
)

// Defines values for EdgeWorkerState.
const (
	EdgeWorkerStateIdle               EdgeWorkerState = "idle"
	EdgeWorkerStateMaintenanceExit    EdgeWorkerState = "maintenance exit"
	EdgeWorkerStateMaintenanceMode    EdgeWorkerState = "maintenance mode"
	EdgeWorkerStateMaintenancePending EdgeWorkerState = "maintenance pending"
	EdgeWorkerStateMaintenanceRequest EdgeWorkerState = "maintenance request"
	EdgeWorkerStateOffline            EdgeWorkerState = "offline"
	EdgeWorkerStateOfflineMaintenance EdgeWorkerState = "offline maintenance"
	EdgeWorkerStateRunning            EdgeWorkerState = "running"
	EdgeWorkerStateShutdownRequest    EdgeWorkerState = "shutdown request"
	EdgeWorkerStateStarting           EdgeWorkerState = "starting"
	EdgeWorkerStateTerminating        EdgeWorkerState = "terminating"
	EdgeWorkerStateUnknown            EdgeWorkerState = "unknown"
)

// Defines values for TaskInstanceState.
const (
	TaskInstanceStateDeferred        TaskInstanceState = "deferred"
	TaskInstanceStateFailed          TaskInstanceState = "failed"
	TaskInstanceStateQueued          TaskInstanceState = "queued"
	TaskInstanceStateRemoved         TaskInstanceState = "removed"
	TaskInstanceStateRestarting      TaskInstanceState = "restarting"
	TaskInstanceStateRunning         TaskInstanceState = "running"
	TaskInstanceStateScheduled       TaskInstanceState = "scheduled"
	TaskInstanceStateSkipped         TaskInstanceState = "skipped"
	TaskInstanceStateSuccess         TaskInstanceState = "success"
	TaskInstanceStateUpForReschedule TaskInstanceState = "up_for_reschedule"
	TaskInstanceStateUpForRetry      TaskInstanceState = "up_for_retry"
	TaskInstanceStateUpstreamFailed  TaskInstanceState = "upstream_failed"
)

// BundleInfo Schema for telling task which bundle to run with.
type BundleInfo struct {
	Name    string  `json:"name"`
	Version *string `json:"version"`
}

// EdgeJobFetched Job that is to be executed on the edge worker.
type EdgeJobFetched struct {
	// Command Execute the given Task.
	Command ExecuteTask `json:"command"`

	// ConcurrencySlots Number of concurrency slots the job requires.
	ConcurrencySlots int `json:"concurrency_slots"`

	// DagId Identifier of the DAG to which the task belongs.
	DagId string `json:"dag_id"`

	// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
	MapIndex int `json:"map_index"`

	// RunId Run ID of the DAG execution.
	RunId string `json:"run_id"`

	// TaskId Task name in the DAG.
	TaskId string `json:"task_id"`

	// TryNumber The number of attempt to execute this task.
	TryNumber int `json:"try_number"`
}

// EdgeWorkerState Status of a Edge Worker instance.
type EdgeWorkerState string

// ExecuteTask Execute the given Task.
type ExecuteTask struct {
	// BundleInfo Schema for telling task which bundle to run with.
	BundleInfo BundleInfo `json:"bundle_info"`
	DagRelPath string     `json:"dag_rel_path"`
	LogPath    *string    `json:"log_path"`

	// Ti Schema for TaskInstance with minimal required fields needed for Executors and Task SDK.
	Ti    TaskInstance `json:"ti"`
	Token string       `json:"token"`
	Type  *string      `json:"type,omitempty"`
}

// HTTPExceptionResponse HTTPException Model used for error response.
type HTTPExceptionResponse struct {
	Detail HTTPExceptionResponse_Detail `json:"detail"`
}

// HTTPExceptionResponseDetail0 defines model for .
type HTTPExceptionResponseDetail0 = string

// HTTPExceptionResponseDetail1 defines model for .
type HTTPExceptionResponseDetail1 map[string]interface{}

// HTTPExceptionResponse_Detail defines model for HTTPExceptionResponse.Detail.
type HTTPExceptionResponse_Detail struct {
	union json.RawMessage
}

// HTTPValidationError defines model for HTTPValidationError.
type HTTPValidationError struct {
	Detail *[]ValidationError `json:"detail,omitempty"`
}

// Job Details of the job sent to the scheduler.
type Job struct {
	// DagId Identifier of the DAG to which the task belongs.
	DagId string `json:"dag_id"`

	// EdgeWorker The worker processing the job during execution.
	EdgeWorker *string `json:"edge_worker"`

	// LastUpdate Last heartbeat of the job.
	LastUpdate *time.Time `json:"last_update"`

	// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
	MapIndex int `json:"map_index"`

	// Queue Queue for which the task is scheduled/running.
	Queue string `json:"queue"`

	// QueuedDttm When the job was queued.
	QueuedDttm *time.Time `json:"queued_dttm"`

	// RunId Run ID of the DAG execution.
	RunId string `json:"run_id"`

	// State All possible states that a Task Instance can be in.
	//
	// Note that None is also allowed, so always use this in a type hint with Optional.
	State TaskInstanceState `json:"state"`

	// TaskId Task name in the DAG.
	TaskId string `json:"task_id"`

	// TryNumber The number of attempt to execute this task.
	TryNumber int `json:"try_number"`
}

// JobCollectionResponse Job Collection serializer.
type JobCollectionResponse struct {
	Jobs         []Job `json:"jobs"`
	TotalEntries int   `json:"total_entries"`
}

// MaintenanceRequest Request body for maintenance operations.
type MaintenanceRequest struct {
	// MaintenanceComment Comment describing the maintenance reason.
	MaintenanceComment string `json:"maintenance_comment"`
}

// PushLogsBody Incremental new log content from worker.
type PushLogsBody struct {
	// LogChunkData Log chunk data as incremental log text.
	LogChunkData string `json:"log_chunk_data"`

	// LogChunkTime Time of the log chunk at point of sending.
	LogChunkTime time.Time `json:"log_chunk_time"`
}

// TaskInstance Schema for TaskInstance with minimal required fields needed for Executors and Task SDK.
type TaskInstance struct {
	ContextCarrier       *map[string]interface{} `json:"context_carrier"`
	DagId                string                  `json:"dag_id"`
	DagVersionId         openapi_types.UUID      `json:"dag_version_id"`
	Id                   openapi_types.UUID      `json:"id"`
	MapIndex             *int                    `json:"map_index,omitempty"`
	ParentContextCarrier *map[string]interface{} `json:"parent_context_carrier"`
	PoolSlots            int                     `json:"pool_slots"`
	PriorityWeight       int                     `json:"priority_weight"`
	Queue                string                  `json:"queue"`
	RunId                string                  `json:"run_id"`
	TaskId               string                  `json:"task_id"`
	TryNumber            int                     `json:"try_number"`
}

// TaskInstanceState All possible states that a Task Instance can be in.
//
// Note that None is also allowed, so always use this in a type hint with Optional.
type TaskInstanceState string

// ValidationError defines model for ValidationError.
type ValidationError struct {
	Loc  []ValidationError_Loc_Item `json:"loc"`
	Msg  string                     `json:"msg"`
	Type string                     `json:"type"`
}

// ValidationErrorLoc0 defines model for .
type ValidationErrorLoc0 = string

// ValidationErrorLoc1 defines model for .
type ValidationErrorLoc1 = int

// ValidationError_Loc_Item defines model for ValidationError.loc.Item.
type ValidationError_Loc_Item struct {
	union json.RawMessage
}

// Worker Details of the worker state sent to the scheduler.
type Worker struct {
	// FirstOnline When the worker was first online.
	FirstOnline *time.Time `json:"first_online"`

	// JobsActive Number of active jobs the worker is running.
	JobsActive *int `json:"jobs_active,omitempty"`

	// LastHeartbeat When the worker last sent a heartbeat.
	LastHeartbeat *time.Time `json:"last_heartbeat"`

	// MaintenanceComments Comments about the maintenance state of the worker.
	MaintenanceComments *string `json:"maintenance_comments"`

	// Queues List of queues the worker is pulling jobs from. If not provided, worker pulls from all queues.
	Queues *[]string `json:"queues"`

	// State Status of a Edge Worker instance.
	State EdgeWorkerState `json:"state"`

	// Sysinfo System information of the worker.
	Sysinfo map[string]Worker_Sysinfo_AdditionalProperties `json:"sysinfo"`

	// WorkerName Name of the worker.
	WorkerName string `json:"worker_name"`
}

// WorkerSysinfo0 defines model for .
type WorkerSysinfo0 = string

// WorkerSysinfo1 defines model for .
type WorkerSysinfo1 = int

// Worker_Sysinfo_AdditionalProperties defines model for Worker.sysinfo.AdditionalProperties.
type Worker_Sysinfo_AdditionalProperties struct {
	union json.RawMessage
}

// WorkerCollectionResponse Worker Collection serializer.
type WorkerCollectionResponse struct {
	TotalEntries int      `json:"total_entries"`
	Workers      []Worker `json:"workers"`
}

// WorkerQueueUpdateBody Changed queues for the worker.
type WorkerQueueUpdateBody struct {
	// NewQueues Additional queues to be added to worker.
	NewQueues *[]string `json:"new_queues"`

	// RemoveQueues Queues to remove from worker.
	RemoveQueues *[]string `json:"remove_queues"`
}

// WorkerQueuesBody Queues that a worker supports to run jobs on.
type WorkerQueuesBody struct {
	// FreeConcurrency Number of free concurrency slots on the worker.
	FreeConcurrency int `json:"free_concurrency"`

	// Queues List of queues the worker is pulling jobs from. If not provided, worker pulls from all queues.
	Queues *[]string `json:"queues"`
}

// WorkerRegistrationReturn The return class for the worker registration.
type WorkerRegistrationReturn struct {
	// LastUpdate Time of the last update of the worker.
	LastUpdate time.Time `json:"last_update"`
}

// WorkerSetStateReturn The return class for the worker set state.
type WorkerSetStateReturn struct {
	// MaintenanceComments Comments about the maintenance state of the worker.
	MaintenanceComments *string `json:"maintenance_comments"`

	// Queues List of queues the worker is pulling jobs from. If not provided, worker pulls from all queues.
	Queues *[]string `json:"queues"`

	// State Status of a Edge Worker instance.
	State EdgeWorkerState `json:"state"`
}

// WorkerStateBody Details of the worker state sent to the scheduler.
type WorkerStateBody struct {
	// JobsActive Number of active jobs the worker is running.
	JobsActive *int `json:"jobs_active,omitempty"`

	// MaintenanceComments Comments about the maintenance state of the worker.
	MaintenanceComments *string `json:"maintenance_comments"`

	// Queues List of queues the worker is pulling jobs from. If not provided, worker pulls from all queues.
	Queues *[]string `json:"queues"`

	// State Status of a Edge Worker instance.
	State EdgeWorkerState `json:"state"`

	// Sysinfo System information of the worker.
	Sysinfo map[string]WorkerStateBody_Sysinfo_AdditionalProperties `json:"sysinfo"`
}

// WorkerStateBodySysinfo0 defines model for .
type WorkerStateBodySysinfo0 = string

// WorkerStateBodySysinfo1 defines model for .
type WorkerStateBodySysinfo1 = int

// WorkerStateBody_Sysinfo_AdditionalProperties defines model for WorkerStateBody.sysinfo.AdditionalProperties.
type WorkerStateBody_Sysinfo_AdditionalProperties struct {
	union json.RawMessage
}

// FetchJSONRequestBody defines body for Fetch for application/json ContentType.
type FetchJSONRequestBody = WorkerQueuesBody

// PushLogsJSONRequestBody defines body for PushLogs for application/json ContentType.
type PushLogsJSONRequestBody = PushLogsBody

// UpdateQueuesJSONRequestBody defines body for UpdateQueues for application/json ContentType.
type UpdateQueuesJSONRequestBody = WorkerQueueUpdateBody

// SetStateJSONRequestBody defines body for SetState for application/json ContentType.
type SetStateJSONRequestBody = WorkerStateBody

// RegisterJSONRequestBody defines body for Register for application/json ContentType.
type RegisterJSONRequestBody = WorkerStateBody

// AsHTTPExceptionResponseDetail0 returns the union data inside the HTTPExceptionResponse_Detail as a HTTPExceptionResponseDetail0
func (t HTTPExceptionResponse_Detail) AsHTTPExceptionResponseDetail0() (HTTPExceptionResponseDetail0, error) {
	var body HTTPExceptionResponseDetail0
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromHTTPExceptionResponseDetail0 overwrites any union data inside the HTTPExceptionResponse_Detail as the provided HTTPExceptionResponseDetail0
func (t *HTTPExceptionResponse_Detail) FromHTTPExceptionResponseDetail0(v HTTPExceptionResponseDetail0) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeHTTPExceptionResponseDetail0 performs a merge with any union data inside the HTTPExceptionResponse_Detail, using the provided HTTPExceptionResponseDetail0
func (t *HTTPExceptionResponse_Detail) MergeHTTPExceptionResponseDetail0(v HTTPExceptionResponseDetail0) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsHTTPExceptionResponseDetail1 returns the union data inside the HTTPExceptionResponse_Detail as a HTTPExceptionResponseDetail1
func (t HTTPExceptionResponse_Detail) AsHTTPExceptionResponseDetail1() (HTTPExceptionResponseDetail1, error) {
	var body HTTPExceptionResponseDetail1
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromHTTPExceptionResponseDetail1 overwrites any union data inside the HTTPExceptionResponse_Detail as the provided HTTPExceptionResponseDetail1
func (t *HTTPExceptionResponse_Detail) FromHTTPExceptionResponseDetail1(v HTTPExceptionResponseDetail1) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeHTTPExceptionResponseDetail1 performs a merge with any union data inside the HTTPExceptionResponse_Detail, using the provided HTTPExceptionResponseDetail1
func (t *HTTPExceptionResponse_Detail) MergeHTTPExceptionResponseDetail1(v HTTPExceptionResponseDetail1) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t HTTPExceptionResponse_Detail) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *HTTPExceptionResponse_Detail) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

// AsValidationErrorLoc0 returns the union data inside the ValidationError_Loc_Item as a ValidationErrorLoc0
func (t ValidationError_Loc_Item) AsValidationErrorLoc0() (ValidationErrorLoc0, error) {
	var body ValidationErrorLoc0
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromValidationErrorLoc0 overwrites any union data inside the ValidationError_Loc_Item as the provided ValidationErrorLoc0
func (t *ValidationError_Loc_Item) FromValidationErrorLoc0(v ValidationErrorLoc0) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeValidationErrorLoc0 performs a merge with any union data inside the ValidationError_Loc_Item, using the provided ValidationErrorLoc0
func (t *ValidationError_Loc_Item) MergeValidationErrorLoc0(v ValidationErrorLoc0) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsValidationErrorLoc1 returns the union data inside the ValidationError_Loc_Item as a ValidationErrorLoc1
func (t ValidationError_Loc_Item) AsValidationErrorLoc1() (ValidationErrorLoc1, error) {
	var body ValidationErrorLoc1
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromValidationErrorLoc1 overwrites any union data inside the ValidationError_Loc_Item as the provided ValidationErrorLoc1
func (t *ValidationError_Loc_Item) FromValidationErrorLoc1(v ValidationErrorLoc1) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeValidationErrorLoc1 performs a merge with any union data inside the ValidationError_Loc_Item, using the provided ValidationErrorLoc1
func (t *ValidationError_Loc_Item) MergeValidationErrorLoc1(v ValidationErrorLoc1) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t ValidationError_Loc_Item) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *ValidationError_Loc_Item) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

// AsWorkerSysinfo0 returns the union data inside the Worker_Sysinfo_AdditionalProperties as a WorkerSysinfo0
func (t Worker_Sysinfo_AdditionalProperties) AsWorkerSysinfo0() (WorkerSysinfo0, error) {
	var body WorkerSysinfo0
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromWorkerSysinfo0 overwrites any union data inside the Worker_Sysinfo_AdditionalProperties as the provided WorkerSysinfo0
func (t *Worker_Sysinfo_AdditionalProperties) FromWorkerSysinfo0(v WorkerSysinfo0) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeWorkerSysinfo0 performs a merge with any union data inside the Worker_Sysinfo_AdditionalProperties, using the provided WorkerSysinfo0
func (t *Worker_Sysinfo_AdditionalProperties) MergeWorkerSysinfo0(v WorkerSysinfo0) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsWorkerSysinfo1 returns the union data inside the Worker_Sysinfo_AdditionalProperties as a WorkerSysinfo1
func (t Worker_Sysinfo_AdditionalProperties) AsWorkerSysinfo1() (WorkerSysinfo1, error) {
	var body WorkerSysinfo1
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromWorkerSysinfo1 overwrites any union data inside the Worker_Sysinfo_AdditionalProperties as the provided WorkerSysinfo1
func (t *Worker_Sysinfo_AdditionalProperties) FromWorkerSysinfo1(v WorkerSysinfo1) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeWorkerSysinfo1 performs a merge with any union data inside the Worker_Sysinfo_AdditionalProperties, using the provided WorkerSysinfo1
func (t *Worker_Sysinfo_AdditionalProperties) MergeWorkerSysinfo1(v WorkerSysinfo1) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t Worker_Sysinfo_AdditionalProperties) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *Worker_Sysinfo_AdditionalProperties) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

// AsWorkerStateBodySysinfo0 returns the union data inside the WorkerStateBody_Sysinfo_AdditionalProperties as a WorkerStateBodySysinfo0
func (t WorkerStateBody_Sysinfo_AdditionalProperties) AsWorkerStateBodySysinfo0() (WorkerStateBodySysinfo0, error) {
	var body WorkerStateBodySysinfo0
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromWorkerStateBodySysinfo0 overwrites any union data inside the WorkerStateBody_Sysinfo_AdditionalProperties as the provided WorkerStateBodySysinfo0
func (t *WorkerStateBody_Sysinfo_AdditionalProperties) FromWorkerStateBodySysinfo0(v WorkerStateBodySysinfo0) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeWorkerStateBodySysinfo0 performs a merge with any union data inside the WorkerStateBody_Sysinfo_AdditionalProperties, using the provided WorkerStateBodySysinfo0
func (t *WorkerStateBody_Sysinfo_AdditionalProperties) MergeWorkerStateBodySysinfo0(v WorkerStateBodySysinfo0) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

// AsWorkerStateBodySysinfo1 returns the union data inside the WorkerStateBody_Sysinfo_AdditionalProperties as a WorkerStateBodySysinfo1
func (t WorkerStateBody_Sysinfo_AdditionalProperties) AsWorkerStateBodySysinfo1() (WorkerStateBodySysinfo1, error) {
	var body WorkerStateBodySysinfo1
	err := json.Unmarshal(t.union, &body)
	return body, err
}

// FromWorkerStateBodySysinfo1 overwrites any union data inside the WorkerStateBody_Sysinfo_AdditionalProperties as the provided WorkerStateBodySysinfo1
func (t *WorkerStateBody_Sysinfo_AdditionalProperties) FromWorkerStateBodySysinfo1(v WorkerStateBodySysinfo1) error {
	b, err := json.Marshal(v)
	t.union = b
	return err
}

// MergeWorkerStateBodySysinfo1 performs a merge with any union data inside the WorkerStateBody_Sysinfo_AdditionalProperties, using the provided WorkerStateBodySysinfo1
func (t *WorkerStateBody_Sysinfo_AdditionalProperties) MergeWorkerStateBodySysinfo1(v WorkerStateBodySysinfo1) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	merged, err := runtime.JSONMerge(t.union, b)
	t.union = merged
	return err
}

func (t WorkerStateBody_Sysinfo_AdditionalProperties) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *WorkerStateBody_Sysinfo_AdditionalProperties) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
	// The endpoint of the server conforming to this interface, with scheme,
	// https://api.deepmap.com for example. This can contain a path relative
	// to the server, such as https://api.deepmap.com/dev-test, and all the
	// paths in the swagger spec will be appended to the server.
	Server string

	*resty.Client

	RequestMiddleware []resty.RequestMiddleware
}

// ClientOption allows setting custom parameters during construction
type ClientOption func(*Client) error

func NewClient(server string, opts ...ClientOption) (ClientInterface, error) {
	// create a client with sane default values
	client := Client{
		Server: server,
		Client: resty.New(),
	}
	client.Client.SetBaseURL(client.Server)
	// mutate client and add all optional params
	for _, o := range opts {
		if err := o(&client); err != nil {
			return nil, err
		}
	}
	// ensure the server URL always has a trailing slash
	if !strings.HasSuffix(client.Server, "/") {
		client.Server += "/"
	}

	return &client, nil
}

// WithClient allows overriding the default [resty.Client], which is
// automatically created using http.Client.
//
// If this is used the `server` base URL argument passed in will not be respected anymore
func WithClient(r *resty.Client) ClientOption {
	return func(c *Client) error {
		c.Client = r
		return nil
	}
}

// WithRoundTripper method sets custom http.Transport or any http.RoundTripper
// compatible interface implementation in the Resty client
func WithRoundTripper(transport http.RoundTripper) ClientOption {
	return func(c *Client) error {
		c.Client.SetTransport(transport)
		return nil
	}
}

// WithRequestMiddleware allows setting up a callback function, which will be
// called right before sending the request. This can be used to mutate the request.
func WithRequestMiddleware(mw resty.RequestMiddleware) ClientOption {
	return func(c *Client) error {
		c.RequestMiddleware = append(c.RequestMiddleware, mw)
		c.Client = c.Client.AddRequestMiddleware(mw)
		return nil
	}
}

func (c *Client) Jobs() JobsClient {
	return &jobsClient{c.Client}
}
func (c *Client) Logs() LogsClient {
	return &logsClient{c.Client}
}
func (c *Client) Worker() WorkerClient {
	return &workerClient{c.Client}
}

type ClientInterface interface {
	// Jobs deals with all the Jobs endpoints
	Jobs() JobsClient
	// Logs deals with all the Logs endpoints
	Logs() LogsClient
	// Worker deals with all the Worker endpoints
	Worker() WorkerClient
}

type GeneralHTTPError struct {
	Response *resty.Response
	JSON     map[string]any
	Text     string
}

var errorTypes = map[int]string{
	1: "informational response",
	3: "redirect response",
	4: "client error",
	5: "server error",
}

func (e GeneralHTTPError) Error() string {
	var b strings.Builder
	kind, ok := errorTypes[e.Response.StatusCode()/100]
	if !ok {
		kind = "unknown HTTP error"
	}
	fmt.Fprintf(&b, "%s '%s'", kind, e.Response.Status())
	if e.JSON != nil {
		fmt.Fprintf(&b, " %v", e.JSON)
	} else {
		fmt.Fprintf(&b, " content=%q", e.Text)
	}
	return b.String()
}

func HandleError(client *resty.Client, resp *resty.Response) error {
	if !resp.IsError() {
		return nil
	}

	e := GeneralHTTPError{Response: resp}

	e.Text = resp.String()
	if resp.Header().Get("content-type") == "application/json" {
		if json.Unmarshal([]byte(e.Text), &e.JSON) == nil {
			e.Text = ""
		}
	}

	// Set the parsed error back into the object so `resp.Error()` returns the populated one!
	resp.Request.SetError(&e)

	return &e
}

type jobsClient struct {
	*resty.Client
}

// FetchResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *jobsClient) FetchResponse(ctx context.Context, workerName string, body *WorkerQueuesBody) (resp *resty.Response, err error) {

	var res struct {
		// Command Execute the given Task.
		Command ExecuteTask `json:"command"`

		// ConcurrencySlots Number of concurrency slots the job requires.
		ConcurrencySlots int `json:"concurrency_slots"`

		// DagId Identifier of the DAG to which the task belongs.
		DagId string `json:"dag_id"`

		// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
		MapIndex int `json:"map_index"`

		// RunId Run ID of the DAG execution.
		RunId string `json:"run_id"`

		// TaskId Task name in the DAG.
		TaskId string `json:"task_id"`

		// TryNumber The number of attempt to execute this task.
		TryNumber int `json:"try_number"`
	}

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "worker_name", runtime.ParamLocationPath, workerName)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("worker_name", pathParam)
	}

	if body == nil {
		return nil, fmt.Errorf("Fetch requires a non-nil body argument")
	}
	resp, err = req.
		SetContentType("application/json").
		SetBody(body).
		Post("edge_worker/v1/jobs/fetch/{worker_name}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *jobsClient) Fetch(ctx context.Context, workerName string, body *WorkerQueuesBody) (*struct {
	// Command Execute the given Task.
	Command ExecuteTask `json:"command"`

	// ConcurrencySlots Number of concurrency slots the job requires.
	ConcurrencySlots int `json:"concurrency_slots"`

	// DagId Identifier of the DAG to which the task belongs.
	DagId string `json:"dag_id"`

	// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
	MapIndex int `json:"map_index"`

	// RunId Run ID of the DAG execution.
	RunId string `json:"run_id"`

	// TaskId Task name in the DAG.
	TaskId string `json:"task_id"`

	// TryNumber The number of attempt to execute this task.
	TryNumber int `json:"try_number"`
}, error) {
	res, err := c.FetchResponse(ctx, workerName, body)
	if err != nil {
		return nil, err
	}

	return res.Result().(*struct {
		// Command Execute the given Task.
		Command ExecuteTask `json:"command"`

		// ConcurrencySlots Number of concurrency slots the job requires.
		ConcurrencySlots int `json:"concurrency_slots"`

		// DagId Identifier of the DAG to which the task belongs.
		DagId string `json:"dag_id"`

		// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
		MapIndex int `json:"map_index"`

		// RunId Run ID of the DAG execution.
		RunId string `json:"run_id"`

		// TaskId Task name in the DAG.
		TaskId string `json:"task_id"`

		// TryNumber The number of attempt to execute this task.
		TryNumber int `json:"try_number"`
	}), nil
}

// StateResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *jobsClient) StateResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, state TaskInstanceState) (resp *resty.Response, err error) {

	var res interface{}

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "dag_id", runtime.ParamLocationPath, dagId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("dag_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "task_id", runtime.ParamLocationPath, taskId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("task_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "run_id", runtime.ParamLocationPath, runId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("run_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "try_number", runtime.ParamLocationPath, tryNumber)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("try_number", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "map_index", runtime.ParamLocationPath, mapIndex)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("map_index", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "state", runtime.ParamLocationPath, state)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("state", pathParam)
	}

	resp, err = req.
		Patch("edge_worker/v1/jobs/state/{dag_id}/{task_id}/{run_id}/{try_number}/{map_index}/{state}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *jobsClient) State(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, state TaskInstanceState) (*interface{}, error) {
	res, err := c.StateResponse(ctx, dagId, taskId, runId, tryNumber, mapIndex, state)
	if err != nil {
		return nil, err
	}

	return res.Result().(*interface{}), nil
}

type logsClient struct {
	*resty.Client
}

// filePathResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *logsClient) filePathResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int) (resp *resty.Response, err error) {

	var res string

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "dag_id", runtime.ParamLocationPath, dagId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("dag_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "task_id", runtime.ParamLocationPath, taskId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("task_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "run_id", runtime.ParamLocationPath, runId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("run_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "try_number", runtime.ParamLocationPath, tryNumber)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("try_number", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "map_index", runtime.ParamLocationPath, mapIndex)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("map_index", pathParam)
	}

	resp, err = req.
		Get("edge_worker/v1/logs/logfile_path/{dag_id}/{task_id}/{run_id}/{try_number}/{map_index}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *logsClient) filePath(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int) (*string, error) {
	res, err := c.filePathResponse(ctx, dagId, taskId, runId, tryNumber, mapIndex)
	if err != nil {
		return nil, err
	}

	return res.Result().(*string), nil
}

// PushResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *logsClient) PushResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, body *PushLogsBody) (resp *resty.Response, err error) {

	var res interface{}

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "dag_id", runtime.ParamLocationPath, dagId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("dag_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "task_id", runtime.ParamLocationPath, taskId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("task_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "run_id", runtime.ParamLocationPath, runId)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("run_id", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "try_number", runtime.ParamLocationPath, tryNumber)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("try_number", pathParam)
	}

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "map_index", runtime.ParamLocationPath, mapIndex)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("map_index", pathParam)
	}

	if body == nil {
		return nil, fmt.Errorf("Push requires a non-nil body argument")
	}
	resp, err = req.
		SetContentType("application/json").
		SetBody(body).
		Post("edge_worker/v1/logs/push/{dag_id}/{task_id}/{run_id}/{try_number}/{map_index}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *logsClient) Push(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, body *PushLogsBody) (*interface{}, error) {
	res, err := c.PushResponse(ctx, dagId, taskId, runId, tryNumber, mapIndex, body)
	if err != nil {
		return nil, err
	}

	return res.Result().(*interface{}), nil
}

type workerClient struct {
	*resty.Client
}

// UpdateQueuesResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *workerClient) UpdateQueuesResponse(ctx context.Context, workerName string, body *WorkerQueueUpdateBody) (resp *resty.Response, err error) {

	var res interface{}

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "worker_name", runtime.ParamLocationPath, workerName)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("worker_name", pathParam)
	}

	if body == nil {
		return nil, fmt.Errorf("UpdateQueues requires a non-nil body argument")
	}
	resp, err = req.
		SetContentType("application/json").
		SetBody(body).
		Patch("edge_worker/v1/worker/queues/{worker_name}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *workerClient) UpdateQueues(ctx context.Context, workerName string, body *WorkerQueueUpdateBody) (*interface{}, error) {
	res, err := c.UpdateQueuesResponse(ctx, workerName, body)
	if err != nil {
		return nil, err
	}

	return res.Result().(*interface{}), nil
}

// SetStateResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *workerClient) SetStateResponse(ctx context.Context, workerName string, body *WorkerStateBody) (resp *resty.Response, err error) {

	var res WorkerSetStateReturn

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "worker_name", runtime.ParamLocationPath, workerName)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("worker_name", pathParam)
	}

	if body == nil {
		return nil, fmt.Errorf("SetState requires a non-nil body argument")
	}
	resp, err = req.
		SetContentType("application/json").
		SetBody(body).
		Patch("edge_worker/v1/worker/{worker_name}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *workerClient) SetState(ctx context.Context, workerName string, body *WorkerStateBody) (*WorkerSetStateReturn, error) {
	res, err := c.SetStateResponse(ctx, workerName, body)
	if err != nil {
		return nil, err
	}

	return res.Result().(*WorkerSetStateReturn), nil
}

// RegisterResponse performs the HTTP request and returns the lower level [resty.Response]
func (c *workerClient) RegisterResponse(ctx context.Context, workerName string, body *WorkerStateBody) (resp *resty.Response, err error) {

	var res WorkerRegistrationReturn

	req := c.R().SetContext(ctx).SetResult(&res)

	{
		pathParam, err := runtime.StyleParamWithLocation("simple", false, "worker_name", runtime.ParamLocationPath, workerName)
		if err != nil {
			return nil, err
		}
		req.SetPathParam("worker_name", pathParam)
	}

	if body == nil {
		return nil, fmt.Errorf("Register requires a non-nil body argument")
	}
	resp, err = req.
		SetContentType("application/json").
		SetBody(body).
		Post("edge_worker/v1/worker/{worker_name}")
	if err != nil {
		return resp, err
	}
	return resp, HandleError(c.Client, resp)
}

func (c *workerClient) Register(ctx context.Context, workerName string, body *WorkerStateBody) (*WorkerRegistrationReturn, error) {
	res, err := c.RegisterResponse(ctx, workerName, body)
	if err != nil {
		return nil, err
	}

	return res.Result().(*WorkerRegistrationReturn), nil
}

type JobsClient interface {
	// Fetch a job to execute on the edge worker.
	Fetch(ctx context.Context, workerName string, body *WorkerQueuesBody) (*struct {
		// Command Execute the given Task.
		Command ExecuteTask `json:"command"`

		// ConcurrencySlots Number of concurrency slots the job requires.
		ConcurrencySlots int `json:"concurrency_slots"`

		// DagId Identifier of the DAG to which the task belongs.
		DagId string `json:"dag_id"`

		// MapIndex For dynamically mapped tasks the mapping number, -1 if the task is not mapped.
		MapIndex int `json:"map_index"`

		// RunId Run ID of the DAG execution.
		RunId string `json:"run_id"`

		// TaskId Task name in the DAG.
		TaskId string `json:"task_id"`

		// TryNumber The number of attempt to execute this task.
		TryNumber int `json:"try_number"`
	}, error)
	// FetchResponse is a lower level version of [Fetch] and provides access to the raw [resty.Response]
	FetchResponse(ctx context.Context, workerName string, body *WorkerQueuesBody) (*resty.Response, error)

	// Update the state of a job running on the edge worker.
	State(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, state TaskInstanceState) (*interface{}, error)
	// StateResponse is a lower level version of [State] and provides access to the raw [resty.Response]
	StateResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, state TaskInstanceState) (*resty.Response, error)
}

var _ JobsClient = (*jobsClient)(nil)

type LogsClient interface {
	// Elaborate the path and filename to expect from task execution.
	filePath(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int) (*string, error)
	// filePathResponse is a lower level version of [filePath] and provides access to the raw [resty.Response]
	filePathResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int) (*resty.Response, error)

	// Push an incremental log chunk from Edge Worker to central site.
	Push(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, body *PushLogsBody) (*interface{}, error)
	// PushResponse is a lower level version of [Push] and provides access to the raw [resty.Response]
	PushResponse(ctx context.Context, dagId string, taskId string, runId string, tryNumber int, mapIndex int, body *PushLogsBody) (*resty.Response, error)
}

var _ LogsClient = (*logsClient)(nil)

type WorkerClient interface {
	UpdateQueues(ctx context.Context, workerName string, body *WorkerQueueUpdateBody) (*interface{}, error)
	// UpdateQueuesResponse is a lower level version of [UpdateQueues] and provides access to the raw [resty.Response]
	UpdateQueuesResponse(ctx context.Context, workerName string, body *WorkerQueueUpdateBody) (*resty.Response, error)

	// Set state of worker and returns the current assigned queues.
	SetState(ctx context.Context, workerName string, body *WorkerStateBody) (*WorkerSetStateReturn, error)
	// SetStateResponse is a lower level version of [SetState] and provides access to the raw [resty.Response]
	SetStateResponse(ctx context.Context, workerName string, body *WorkerStateBody) (*resty.Response, error)

	// Register a new worker to the backend.
	Register(ctx context.Context, workerName string, body *WorkerStateBody) (*WorkerRegistrationReturn, error)
	// RegisterResponse is a lower level version of [Register] and provides access to the raw [resty.Response]
	RegisterResponse(ctx context.Context, workerName string, body *WorkerStateBody) (*resty.Response, error)
}

var _ WorkerClient = (*workerClient)(nil)
