// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.

package plexgo

// Generated from OpenAPI doc version 1.1.1 and generator version 2.767.2

import (
	"context"
	"fmt"
	"github.com/LukeHagar/plexgo/internal/config"
	"github.com/LukeHagar/plexgo/internal/globals"
	"github.com/LukeHagar/plexgo/internal/hooks"
	"github.com/LukeHagar/plexgo/internal/utils"
	"github.com/LukeHagar/plexgo/models/components"
	"github.com/LukeHagar/plexgo/retry"
	"net/http"
	"time"
)

// ServerList contains the list of servers available to the SDK
var ServerList = []string{
	"https://{IP-description}.{identifier}.plex.direct:{port}",
	"{protocol}://{host}:{port}",
	"https://{full_server_url}",
}

// HTTPClient provides an interface for supplying the SDK with a custom HTTP client
type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

// String provides a helper function to return a pointer to a string
func String(s string) *string { return &s }

// Bool provides a helper function to return a pointer to a bool
func Bool(b bool) *bool { return &b }

// Int provides a helper function to return a pointer to an int
func Int(i int) *int { return &i }

// Int64 provides a helper function to return a pointer to an int64
func Int64(i int64) *int64 { return &i }

// Float32 provides a helper function to return a pointer to a float32
func Float32(f float32) *float32 { return &f }

// Float64 provides a helper function to return a pointer to a float64
func Float64(f float64) *float64 { return &f }

// Pointer provides a helper function to return a pointer to a type
func Pointer[T any](v T) *T { return &v }

type PlexAPI struct {
	SDKVersion string
	// General endpoints for basic PMS operation not specific to any media provider
	General *General
	// The server can notify clients in real-time of a wide range of events, from library scanning, to preferences being modified, to changes to media, and many other things. This is also the mechanism by which activity progress is reported.
	//
	// Two protocols for receiving the events are available: EventSource (also known as SSE), and WebSocket.
	//
	Events *Events
	// API Operations against the Preferences
	Preferences *Preferences
	// Operations for rating media items (thumbs up/down, star ratings, etc.)
	Rate *Rate
	// The actions feature within a media provider
	Timeline *Timeline
	// Activities provide a way to monitor and control asynchronous operations on the server. In order to receive real-time updates for activities, a client would normally subscribe via either EventSource or Websocket endpoints.
	//
	// Activities are associated with HTTP replies via a special `X-Plex-Activity` header which contains the UUID of the activity.
	//
	// Activities are optional cancellable. If cancellable, they may be cancelled via the `DELETE` endpoint.
	//
	Activities *Activities
	// The butler is responsible for running periodic tasks.  Some tasks run daily, others every few days, and some weekly.  These includes database maintenance, metadata updating, thumbnail generation, media analysis, and other tasks.
	Butler *Butler
	// API Operations against the Download Queue
	DownloadQueue *DownloadQueue
	// The hubs within a media provider
	Hubs *Hubs
	// The search feature within a media provider
	Search *Search
	// Library endpoints which are outside of the Media Provider API.  Typically this is manipulation of the library (adding/removing sections, modifying preferences, etc).
	Library *Library
	// API Operations against the Collections
	Collections *Collections
	// The DVR provides means to watch and record live TV.  This section of endpoints describes how to setup the DVR itself
	//
	DVRs *DVRs
	// The EPG (Electronic Program Guide) is responsible for obtaining metadata for what is airing on each channel and when
	//
	Epg *Epg
	// LiveTV contains the playback sessions of a channel from a DVR device
	//
	LiveTV *LiveTV
	// Logging mechanism to allow clients to log to the server
	Log *Log
	// Media grabbers provide ways for media to be obtained for a given protocol. The simplest ones are `stream` and `download`. More complex grabbers can have associated devices
	//
	// Network tuners can present themselves on the network using the Simple Service Discovery Protocol and Plex Media Server will discover them. The following XML is an example of the data returned from SSDP. The `deviceType`, `serviceType`, and `serviceId` values must remain as they are in the example in order for PMS to properly discover the device. Other less-obvious fields are described in the parameters section below.
	//
	// Example SSDP output
	// ```
	// <root xmlns="urn:schemas-upnp-org:device-1-0">
	//     <specVersion>
	//         <major>1</major>
	//         <minor>0</minor>
	//     </specVersion>
	//     <device>
	//         <deviceType>urn:plex-tv:device:Media:1</deviceType>
	//         <friendlyName>Turing Hopper 3000</friendlyName>
	//         <manufacturer>Plex, Inc.</manufacturer>
	//         <manufacturerURL>https://plex.tv/</manufacturerURL>
	//         <modelDescription>Turing Hopper 3000 Media Grabber</modelDescription>
	//         <modelName>Plex Media Grabber</modelName>
	//         <modelNumber>1</modelNumber>
	//         <modelURL>https://plex.tv</modelURL>
	//         <UDN>uuid:42fde8e4-93b6-41e5-8a63-12d848655811</UDN>
	//         <serviceList>
	//             <service>
	//                 <URLBase>http://10.0.0.5:8088</URLBase>
	//                 <serviceType>urn:plex-tv:service:MediaGrabber:1</serviceType>
	//                 <serviceId>urn:plex-tv:serviceId:MediaGrabber</serviceId>
	//             </service>
	//         </serviceList>
	//     </device>
	// </root>
	// ```
	//
	//   - UDN: (string) A UUID for the device. This should be unique across models of a device at minimum.
	//   - URLBase: (string) The base HTTP URL for the device from which all of the other endpoints are hosted.
	//
	Devices *Devices
	// Media providers are the starting points for the entire Plex Media Server media library API.  It defines the paths for the groups of endpoints.  The `/media/providers` should be the only hard-coded path in clients when accessing the media library.  Non-media library endpoints are outside the scope of the media provider.  See the description in See [the section in API Info](#section/API-Info/Media-Providers) for more information on how to use media providers.
	Provider *Provider
	// Subscriptions determine which media will be recorded and the criteria for selecting an airing when multiple are available
	//
	Subscriptions *Subscriptions
	// API Operations against the Transcoder
	Transcoder *Transcoder
	// Media playlists that can be created and played back
	Playlist *Playlist
	// Endpoints for manipulating playlists.
	LibraryPlaylists *LibraryPlaylists
	// The playqueue feature within a media provider
	// A play queue represents the current list of media for playback. Although queues are persisted by the server, they should be regarded by the user as a fairly lightweight, an ephemeral list of items queued up for playback in a session.  There is generally one active queue for each type of media (music, video, photos) that can be added to or destroyed and replaced with a fresh queue.
	// Play Queues has a region, which we refer to in this doc (partially for historical reasons) as "Up Next". This region is defined by `playQueueLastAddedItemID` existing on the media container. This follows iTunes' terminology. It is a special region after the currently playing item but before the originally-played items. This enables "Party Mode" listening/viewing, where items can be added on-the-fly, and normal queue playback resumed when completed.
	// You can visualize the play queue as a sliding window in the complete list of media queued for playback. This model is important when scaling to larger play queues (e.g. shuffling 40,000 audio tracks). The client only needs visibility into small areas of the queue at any given time, and the server can optimize access in this fashion.
	// All created play queues will have an empty "Up Next" area - unless the item is an album and no `key` is provided. In this case the "Up Next" area will be populated by the contents of the album. This is to allow queueing of multiple albums - since the 'Add to Up Next' will insert after all the tracks. This means that If you're creating a PQ from an album, you can only shuffle it if you set `key`. This is due to the above implicit queueing of albums when no `key` is provided as well as the current limitation that you cannot shuffle a PQ with an "Up Next" area.
	// The play queue window advances as the server receives timeline requests. The client needs to retrieve the play queue as the “now playing” item changes. There is no play queue API to update the playing item.
	PlayQueue *PlayQueue
	// Service provided to compute UltraBlur colors and images.
	UltraBlur *UltraBlur
	// The status endpoints give you information about current playbacks, play history, and even terminating sessions.
	Status *Status
	// This describes the API for searching and applying updates to the Plex Media Server.
	// Updates to the status can be observed via the Event API.
	//
	Updater        *Updater
	Authentication *Authentication
	Users          *Users
	Plex           *Plex
	// The actual content of the media provider
	Content *Content
	// Endpoints for manipulating collections.  In addition to these endpoints, `/library/collections/:collectionId/X` will be rerouted to `/library/metadata/:collectionId/X` and respond to those endpoints as well.
	LibraryCollections *LibraryCollections

	sdkConfiguration config.SDKConfiguration
	hooks            *hooks.Hooks
}

type SDKOption func(*PlexAPI)

// WithServerURL allows the overriding of the default server URL
func WithServerURL(serverURL string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.ServerURL = serverURL
	}
}

// WithTemplatedServerURL allows the overriding of the default server URL with a templated URL populated with the provided parameters
func WithTemplatedServerURL(serverURL string, params map[string]string) SDKOption {
	return func(sdk *PlexAPI) {
		if params != nil {
			serverURL = utils.ReplaceParameters(serverURL, params)
		}

		sdk.sdkConfiguration.ServerURL = serverURL
	}
}

// WithServerIndex allows the overriding of the default server by index
func WithServerIndex(serverIndex int) SDKOption {
	return func(sdk *PlexAPI) {
		if serverIndex < 0 || serverIndex >= len(ServerList) {
			panic(fmt.Errorf("server index %d out of range", serverIndex))
		}

		sdk.sdkConfiguration.ServerIndex = serverIndex
	}
}

// WithIdentifier allows setting the identifier variable for url substitution
func WithIdentifier(identifier string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["identifier"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["identifier"] = fmt.Sprintf("%v", identifier)
		}
	}
}

// WithIPDescription allows setting the IP-description variable for url substitution
func WithIPDescription(ipDescription string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["IP-description"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["IP-description"] = fmt.Sprintf("%v", ipDescription)
		}
	}
}

// WithPort allows setting the port variable for url substitution
func WithPort(port string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["port"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["port"] = fmt.Sprintf("%v", port)
		}
	}
}

// WithProtocol allows setting the protocol variable for url substitution
func WithProtocol(protocol string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["protocol"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["protocol"] = fmt.Sprintf("%v", protocol)
		}
	}
}

// WithHost allows setting the host variable for url substitution
func WithHost(host string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["host"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["host"] = fmt.Sprintf("%v", host)
		}
	}
}

// WithFullServerURL allows setting the full_server_url variable for url substitution
func WithFullServerURL(fullServerURL string) SDKOption {
	return func(sdk *PlexAPI) {
		for idx := range sdk.sdkConfiguration.ServerVariables {
			if _, ok := sdk.sdkConfiguration.ServerVariables[idx]["full_server_url"]; !ok {
				continue
			}

			sdk.sdkConfiguration.ServerVariables[idx]["full_server_url"] = fmt.Sprintf("%v", fullServerURL)
		}
	}
}

// WithClient allows the overriding of the default HTTP client used by the SDK
func WithClient(client HTTPClient) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Client = client
	}
}

// WithSecurity configures the SDK to use the provided security details
func WithSecurity(token string) SDKOption {
	return func(sdk *PlexAPI) {
		security := components.Security{Token: &token}
		sdk.sdkConfiguration.Security = utils.AsSecuritySource(&security)
	}
}

// WithSecuritySource configures the SDK to invoke the Security Source function on each method call to determine authentication
func WithSecuritySource(security func(context.Context) (components.Security, error)) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Security = func(ctx context.Context) (interface{}, error) {
			return security(ctx)
		}
	}
}

// WithAccepts allows setting the Accepts parameter for all supported operations
func WithAccepts(accepts components.Accepts) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Accepts = &accepts
	}
}

// WithClientIdentifier allows setting the ClientIdentifier parameter for all supported operations
func WithClientIdentifier(clientIdentifier string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.ClientIdentifier = &clientIdentifier
	}
}

// WithProduct allows setting the Product parameter for all supported operations
func WithProduct(product string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Product = &product
	}
}

// WithVersion allows setting the Version parameter for all supported operations
func WithVersion(version string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Version = &version
	}
}

// WithPlatform allows setting the Platform parameter for all supported operations
func WithPlatform(platform string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Platform = &platform
	}
}

// WithPlatformVersion allows setting the PlatformVersion parameter for all supported operations
func WithPlatformVersion(platformVersion string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.PlatformVersion = &platformVersion
	}
}

// WithDevice allows setting the Device parameter for all supported operations
func WithDevice(device string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Device = &device
	}
}

// WithModel allows setting the Model parameter for all supported operations
func WithModel(model string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Model = &model
	}
}

// WithDeviceVendor allows setting the DeviceVendor parameter for all supported operations
func WithDeviceVendor(deviceVendor string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.DeviceVendor = &deviceVendor
	}
}

// WithDeviceName allows setting the DeviceName parameter for all supported operations
func WithDeviceName(deviceName string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.DeviceName = &deviceName
	}
}

// WithMarketplace allows setting the Marketplace parameter for all supported operations
func WithMarketplace(marketplace string) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Globals.Marketplace = &marketplace
	}
}

func WithRetryConfig(retryConfig retry.Config) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.RetryConfig = &retryConfig
	}
}

// WithTimeout Optional request timeout applied to each operation
func WithTimeout(timeout time.Duration) SDKOption {
	return func(sdk *PlexAPI) {
		sdk.sdkConfiguration.Timeout = &timeout
	}
}

// New creates a new instance of the SDK with the provided options
func New(opts ...SDKOption) *PlexAPI {
	sdk := &PlexAPI{
		SDKVersion: "0.28.0",
		sdkConfiguration: config.SDKConfiguration{
			UserAgent:  "speakeasy-sdk/go 0.28.0 2.767.2 1.1.1 github.com/LukeHagar/plexgo",
			Globals:    globals.Globals{},
			ServerList: ServerList,
			ServerVariables: []map[string]string{
				{
					"identifier":     "0123456789abcdef0123456789abcdef",
					"IP-description": "1-2-3-4",
					"port":           "32400",
				},
				{
					"protocol": "http",
					"host":     "localhost",
					"port":     "32400",
				},
				{
					"full_server_url": "http://localhost:32400",
				},
			},
		},
		hooks: hooks.New(),
	}
	for _, opt := range opts {
		opt(sdk)
	}

	// Use WithClient to override the default client if you would like to customize the timeout
	if sdk.sdkConfiguration.Client == nil {
		sdk.sdkConfiguration.Client = &http.Client{Timeout: 60 * time.Second}
	}

	currentServerURL, _ := sdk.sdkConfiguration.GetServerDetails()
	serverURL := currentServerURL
	serverURL, sdk.sdkConfiguration.Client = sdk.hooks.SDKInit(currentServerURL, sdk.sdkConfiguration.Client)
	if currentServerURL != serverURL {
		sdk.sdkConfiguration.ServerURL = serverURL
	}

	sdk.General = newGeneral(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Events = newEvents(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Preferences = newPreferences(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Rate = newRate(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Timeline = newTimeline(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Activities = newActivities(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Butler = newButler(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.DownloadQueue = newDownloadQueue(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Hubs = newHubs(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Search = newSearch(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Library = newLibrary(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Collections = newCollections(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.DVRs = newDVRs(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Epg = newEpg(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.LiveTV = newLiveTV(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Log = newLog(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Devices = newDevices(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Provider = newProvider(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Subscriptions = newSubscriptions(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Transcoder = newTranscoder(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Playlist = newPlaylist(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.LibraryPlaylists = newLibraryPlaylists(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.PlayQueue = newPlayQueue(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.UltraBlur = newUltraBlur(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Status = newStatus(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Updater = newUpdater(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Authentication = newAuthentication(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Users = newUsers(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Plex = newPlex(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.Content = newContent(sdk, sdk.sdkConfiguration, sdk.hooks)
	sdk.LibraryCollections = newLibraryCollections(sdk, sdk.sdkConfiguration, sdk.hooks)

	return sdk
}
