package assets

import (
	"github.com/secureworks/taegis-sdk-go/client"
	"github.com/secureworks/taegis-sdk-go/graphql"
	"context"
	"net/http"
	"time"
)

type Client struct {
	client *client.Client
	url    string
}

func New(url string, opts ...client.Option) *Client {
	client := client.NewClient(opts...)
	return &Client{
		client: client,
		url:    url,
	}
}

func (c *Client) makeRequest(ctx context.Context, req *graphql.Request, res interface{}) error {
	header := http.Header{}
	return graphql.ExecuteQueryContext(ctx, &graphql.QueryConfig{
		HClient:   c.client,
		Header:    header,
		Output:    res,
		Request:   req,
		ServerURL: c.url,
	})
}

const allAssetFields = `
	id
	hostId
	rn
	tenantId
	sensorTenant
	sensorId
	ingestTime
	createdAt
	updatedAt
	deletedAt
	biosSerial
	firstDiskSerial
	systemVolumeSerial
	sensorVersion
	endpointType
	endpointPlatform
	hostnames {` + allHostnameFields + `
	}
	ethernetAddresses {` + allEthernetAddressFields + `
	}
	ipAddresses {` + allIpAddressFields + `
	}
	users {` + allUserFields + `
	}
	architecture
	osFamily
	osVersion
	osDistributor
	osRelease
	systemType
	osCodename
	kernelRelease
	kernelVersion
	tags {` + allTagFields + `
	}
`

const allAssetCountsFields = `
	count
`

const allAssetCountsByEndpointTypeFields = `
	endpointType
	count
`

const allAssetHistoryFields = `
	id
	createdAt
	updatedAt
	assetId
	tenantId
	hostId
	action
	who
	reason
`

const allAssetHistoryContactFields = `
	email
	name
	sub
`

const allAssetHistoryEventFields = `
	domainName
	hostName
`

const allAssetHistoryIdFields = `
	hostId
	instanceId
`

const allAssetRedCloakHistoryFields = `
	action
	allowedDomain
	assetId
	contact {` + allAssetHistoryContactFields + `
	}
	createdAt
	event {` + allAssetHistoryEventFields + `
	}
	id {` + allAssetHistoryIdFields + `
	}
	reason
	tenantId
`

const allAssetsExportOutputFields = `
	columnDef
	rows
	totalCount
`

const allAssetsResultFields = `
	totalResults
	offset
	limit
	assets {` + allAssetFields + `
	}
`

const allEndpointInfoFields = `
	actualIsolationStatus
	allowedDomain
	color
	desiredIsolationStatus
	firstConnectTime
	hostId
	hostName
	ignitionDetails {` + allIgnitionDetailsFields + `
	}
	lastConnectAddress
	lastConnectServer
	lastConnectTime
	lastCrashCheck
	lastModuleStatusTime
	lastPredicateAuthtap
	lastPredicateCyclorama
	lastPredicateEntwine
	lastPredicateGroundling
	lastPredicateHostel
	lastPredicateLacuna
	lastPredicateMukluk
	lastPredicatePeriodicscanControl
	lastPredicatePeriodicscanResult
	lastPredicateProcwall
	lastPredicateSystemInformation
	moduleHealth {` + allModuleHealthFields + `
	}
	moduleStatus {` + allModuleStatusFields + `
	}
	notableEventCount
	sensorVersion
	systemInformation {` + allSystemInformationFields + `
	}
`

const allEthernetAddressFields = `
	id
	createdAt
	updatedAt
	hostId
	mac
`

const allHostnameFields = `
	id
	createdAt
	updatedAt
	hostId
	hostname
`

const allIgnitionDetailsFields = `
	isEndpointConfigExist
	requestStatus
`

const allIpAddressFields = `
	id
	createdAt
	updatedAt
	ip
	hostId
`

const allModuleHealthFields = `
	enabled
	lastPredicateTime
	lastRunningTime
	moduleColor
	moduleDisplayName
`

const allModuleStatusFields = `
	enabled
	moduleName
	moduleState
`

const allSystemInformationFields = `
	architecture
	biosSerial
	ethernetAddress
	firstDiskSerial
	hostName
	ipAddress
	isServerR2For2003And2008
	productType
	redcloakVersion
	servicePack
	systemVolumeSerial
	windowsVersion
`

const allTagFields = `
	id
	hostId
	tenantId
	createdAt
	updatedAt
	tag
`

const allUpdateTagFields = `
	id
	tenantId
	tag
`

const allUserFields = `
	id
	createdAt
	updatedAt
	hostId
	username
`

type AgentType string

const (
	AgentTypeEndpointRedcloak       AgentType = "ENDPOINT_REDCLOAK"
	AgentTypeEndpointCarbonBlack    AgentType = "ENDPOINT_CARBON_BLACK"
	AgentTypeEndpointCrowdStrike    AgentType = "ENDPOINT_CROWD_STRIKE"
	AgentTypeEndpointMicrosoftAtp   AgentType = "ENDPOINT_MICROSOFT_ATP"
	AgentTypeEndpointCarbonBlackPsc AgentType = "ENDPOINT_CARBON_BLACK_PSC"
)

type Asset struct {
	ID                 string            `json:"id"`
	HostId             string            `json:"hostId"`
	Rn                 string            `json:"rn"`
	TenantId           string            `json:"tenantId"`
	SensorTenant       string            `json:"sensorTenant"`
	SensorId           string            `json:"sensorId"`
	IngestTime         time.Time         `json:"ingestTime"`
	CreatedAt          time.Time         `json:"createdAt"`
	UpdatedAt          time.Time         `json:"updatedAt"`
	DeletedAt          *time.Time        `json:"deletedAt"`
	BiosSerial         *string           `json:"biosSerial"`
	FirstDiskSerial    *string           `json:"firstDiskSerial"`
	SystemVolumeSerial *string           `json:"systemVolumeSerial"`
	SensorVersion      *string           `json:"sensorVersion"`
	EndpointType       *string           `json:"endpointType"`
	EndpointPlatform   *string           `json:"endpointPlatform"`
	Hostnames          []Hostname        `json:"hostnames"`
	EthernetAddresses  []EthernetAddress `json:"ethernetAddresses"`
	IpAddresses        []IpAddress       `json:"ipAddresses"`
	Users              []User            `json:"users"`
	Architecture       *string           `json:"architecture"`
	OsFamily           *string           `json:"osFamily"`
	OsVersion          *string           `json:"osVersion"`
	OsDistributor      *string           `json:"osDistributor"`
	OsRelease          *string           `json:"osRelease"`
	SystemType         *string           `json:"systemType"`
	OsCodename         *string           `json:"osCodename"`
	KernelRelease      *string           `json:"kernelRelease"`
	KernelVersion      *string           `json:"kernelVersion"`
	Tags               []Tag             `json:"tags"`
}

type AssetCounts struct {
	Count int `json:"count"`
}

type AssetCountsByEndpointType struct {
	EndpointType string `json:"endpointType"`
	Count        int    `json:"count"`
}

type AssetHistory struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	AssetId   string    `json:"assetId"`
	TenantId  string    `json:"tenantId"`
	HostId    string    `json:"hostId"`
	Action    string    `json:"action"`
	Who       string    `json:"who"`
	Reason    string    `json:"reason"`
}

type AssetHistoryContact struct {
	Email *string `json:"email"`
	Name  *string `json:"name"`
	Sub   *string `json:"sub"`
}

type AssetHistoryEvent struct {
	DomainName *string `json:"domainName"`
	HostName   *string `json:"hostName"`
}

type AssetHistoryId struct {
	HostId     *string `json:"hostId"`
	InstanceId *string `json:"instanceId"`
}

type AssetInput struct {
	ID   string   `json:"id"`
	Tags []string `json:"tags"`
}

type AssetRedCloakHistory struct {
	Action        *string              `json:"action"`
	AllowedDomain []string             `json:"allowedDomain"`
	AssetId       *string              `json:"assetId"`
	Contact       *AssetHistoryContact `json:"contact"`
	CreatedAt     *string              `json:"createdAt"`
	Event         *AssetHistoryEvent   `json:"event"`
	ID            *AssetHistoryId      `json:"id"`
	Reason        *string              `json:"reason"`
	TenantId      *string              `json:"tenantId"`
}

type AssetStateFilter string

const (
	AssetStateFilterAll       AssetStateFilter = "All"
	AssetStateFilterDeleted   AssetStateFilter = "Deleted"
	AssetStateFilterActive    AssetStateFilter = "Active"
	AssetStateFilterUnhealthy AssetStateFilter = "Unhealthy"
)

type AssetsExportOutput struct {
	ColumnDef  []string `json:"columnDef"`
	Rows       []string `json:"rows"`
	TotalCount *int     `json:"totalCount"`
}

type AssetsOrderByInput string

const (
	AssetsOrderByInputHostname      AssetsOrderByInput = "hostname"
	AssetsOrderByInputIpAddress     AssetsOrderByInput = "ip_address"
	AssetsOrderByInputMacAddress    AssetsOrderByInput = "mac_address"
	AssetsOrderByInputTag           AssetsOrderByInput = "tag"
	AssetsOrderByInputUsername      AssetsOrderByInput = "username"
	AssetsOrderByInputOsVersion     AssetsOrderByInput = "os_version"
	AssetsOrderByInputEndpointType  AssetsOrderByInput = "endpoint_type"
	AssetsOrderByInputCreatedAt     AssetsOrderByInput = "created_at"
	AssetsOrderByInputUpdatedAt     AssetsOrderByInput = "updated_at"
	AssetsOrderByInputDeletedAt     AssetsOrderByInput = "deleted_at"
	AssetsOrderByInputOsFamily      AssetsOrderByInput = "os_family"
	AssetsOrderByInputOsDistributor AssetsOrderByInput = "os_distributor"
)

type AssetsOrderDirectionInput string

const (
	AssetsOrderDirectionInputAsc  AssetsOrderDirectionInput = "asc"
	AssetsOrderDirectionInputDesc AssetsOrderDirectionInput = "desc"
)

type AssetsResult struct {
	TotalResults int     `json:"totalResults"`
	Offset       int     `json:"offset"`
	Limit        int     `json:"limit"`
	Assets       []Asset `json:"assets"`
}

type EndpointInfo struct {
	ActualIsolationStatus            *bool              `json:"actualIsolationStatus"`
	AllowedDomain                    []string           `json:"allowedDomain"`
	Color                            *string            `json:"color"`
	DesiredIsolationStatus           *bool              `json:"desiredIsolationStatus"`
	FirstConnectTime                 *string            `json:"firstConnectTime"`
	HostId                           *string            `json:"hostId"`
	HostName                         *string            `json:"hostName"`
	IgnitionDetails                  *IgnitionDetails   `json:"ignitionDetails"`
	LastConnectAddress               *string            `json:"lastConnectAddress"`
	LastConnectServer                *string            `json:"lastConnectServer"`
	LastConnectTime                  *string            `json:"lastConnectTime"`
	LastCrashCheck                   *string            `json:"lastCrashCheck"`
	LastModuleStatusTime             *string            `json:"lastModuleStatusTime"`
	LastPredicateAuthtap             *string            `json:"lastPredicateAuthtap"`
	LastPredicateCyclorama           *string            `json:"lastPredicateCyclorama"`
	LastPredicateEntwine             *string            `json:"lastPredicateEntwine"`
	LastPredicateGroundling          *string            `json:"lastPredicateGroundling"`
	LastPredicateHostel              *string            `json:"lastPredicateHostel"`
	LastPredicateLacuna              *string            `json:"lastPredicateLacuna"`
	LastPredicateMukluk              *string            `json:"lastPredicateMukluk"`
	LastPredicatePeriodicscanControl *string            `json:"lastPredicatePeriodicscanControl"`
	LastPredicatePeriodicscanResult  *string            `json:"lastPredicatePeriodicscanResult"`
	LastPredicateProcwall            *string            `json:"lastPredicateProcwall"`
	LastPredicateSystemInformation   *string            `json:"lastPredicateSystemInformation"`
	ModuleHealth                     []ModuleHealth     `json:"moduleHealth"`
	ModuleStatus                     []ModuleStatus     `json:"moduleStatus"`
	NotableEventCount                *int               `json:"notableEventCount"`
	SensorVersion                    *int               `json:"sensorVersion"`
	SystemInformation                *SystemInformation `json:"systemInformation"`
}

type EthernetAddress struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Mac       string    `json:"mac"`
}

type Hostname struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Hostname  string    `json:"hostname"`
}

type IgnitionDetails struct {
	IsEndpointConfigExist *bool   `json:"isEndpointConfigExist"`
	RequestStatus         *string `json:"requestStatus"`
}

type IpAddress struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	Ip        string    `json:"ip"`
	HostId    string    `json:"hostId"`
}

type ModuleHealth struct {
	Enabled           *string `json:"enabled"`
	LastPredicateTime *string `json:"lastPredicateTime"`
	LastRunningTime   *string `json:"lastRunningTime"`
	ModuleColor       *string `json:"moduleColor"`
	ModuleDisplayName *string `json:"moduleDisplayName"`
}

type ModuleStatus struct {
	Enabled     *bool   `json:"enabled"`
	ModuleName  *string `json:"moduleName"`
	ModuleState *string `json:"moduleState"`
}

type SearchAssetsInput struct {
	Hostname           *string           `json:"hostname"`
	HostId             *string           `json:"host_id"`
	IpAddress          *string           `json:"ip_address"`
	MacAddress         *string           `json:"mac_address"`
	OsVersion          *string           `json:"os_version"`
	OsFamily           *string           `json:"os_family"`
	OsDistributor      *string           `json:"os_distributor"`
	Username           *string           `json:"username"`
	EndpointType       *string           `json:"endpoint_type"`
	Tag                *string           `json:"tag"`
	HostIdPartialMatch *bool             `json:"host_id_partial_match"`
	OnlyMostRecent     *bool             `json:"only_most_recent"`
	OrSearch           *bool             `json:"or_search"`
	FilterAssetState   *AssetStateFilter `json:"filter_asset_state"`
}

type SearchAssetsPaginationInput struct {
	Offset         *int                       `json:"offset"`
	Limit          *int                       `json:"limit"`
	OrderBy        *AssetsOrderByInput        `json:"order_by"`
	OrderDirection *AssetsOrderDirectionInput `json:"order_direction"`
}

type SystemInformation struct {
	Architecture             *string  `json:"architecture"`
	BiosSerial               *string  `json:"biosSerial"`
	EthernetAddress          []string `json:"ethernetAddress"`
	FirstDiskSerial          *string  `json:"firstDiskSerial"`
	HostName                 *string  `json:"hostName"`
	IpAddress                []string `json:"ipAddress"`
	IsServerR2For2003And2008 *bool    `json:"isServerR2For2003And2008"`
	ProductType              *string  `json:"productType"`
	RedcloakVersion          *int     `json:"redcloakVersion"`
	ServicePack              *string  `json:"servicePack"`
	SystemVolumeSerial       *string  `json:"systemVolumeSerial"`
	WindowsVersion           *string  `json:"windowsVersion"`
}

type Tag struct {
	ID        string    `json:"id"`
	HostId    string    `json:"hostId"`
	TenantId  string    `json:"tenantId"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	Tag       string    `json:"tag"`
}

type UpdateTag struct {
	ID       string `json:"id"`
	TenantId string `json:"tenantId"`
	Tag      string `json:"tag"`
}

type User struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Username  string    `json:"username"`
}

func (c *Client) GetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		tag(id: $id) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		Tag Tag `json:"tag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.Tag, nil
}

func (c *Client) GetTag(id string, opts ...graphql.RequestOption) (Tag, error) {
	return c.GetTagCtx(context.Background(), id, opts...)
}

func (c *Client) GetAssetCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		asset(id: $id) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		Asset Asset `json:"asset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.Asset, nil
}

func (c *Client) GetAsset(id string, opts ...graphql.RequestOption) (Asset, error) {
	return c.GetAssetCtx(context.Background(), id, opts...)
}

func (c *Client) GetAssetsByTagCtx(ctx context.Context, tags []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($tags: [String!]!) {
		assetsByTag(tags: $tags) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("tags", tags)

	var res struct {
		AssetsByTag []*Asset `json:"assetsByTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByTag, nil
}

func (c *Client) GetAssetsByTag(tags []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByTagCtx(context.Background(), tags, opts...)
}

func (c *Client) GetAllUniqueTagsCtx(ctx context.Context, opts ...graphql.RequestOption) ([]string, error) {
	req := graphql.NewRequest(`query {
		allUniqueTags
	}`, opts...)

	var res struct {
		AllUniqueTags []string `json:"allUniqueTags"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllUniqueTags, nil
}

func (c *Client) GetAllUniqueTags(opts ...graphql.RequestOption) ([]string, error) {
	return c.GetAllUniqueTagsCtx(context.Background(), opts...)
}

func (c *Client) GetAssetEndpointInfoCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (EndpointInfo, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		assetEndpointInfo(id: $id) {`+allEndpointInfoFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		AssetEndpointInfo EndpointInfo `json:"assetEndpointInfo"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return EndpointInfo{}, err
	}

	return res.AssetEndpointInfo, nil
}

func (c *Client) GetAssetEndpointInfo(id string, opts ...graphql.RequestOption) (EndpointInfo, error) {
	return c.GetAssetEndpointInfoCtx(context.Background(), id, opts...)
}

type GetAllAssetsArguments struct {
	Offset           *int                       `json:"offset"`
	Limit            *int                       `json:"limit"`
	OrderBy          *AssetsOrderByInput        `json:"order_by"`
	OrderDirection   *AssetsOrderDirectionInput `json:"order_direction"`
	FilterAssetState *AssetStateFilter          `json:"filter_asset_state"`
}

func (c *Client) GetAllAssetsCtx(ctx context.Context, params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int, $order_by: AssetsOrderByInput, $order_direction: AssetsOrderDirectionInput, $filter_asset_state: AssetStateFilter) {
		allAssets(offset: $offset, limit: $limit, order_by: $order_by, order_direction: $order_direction, filter_asset_state: $filter_asset_state) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", params.Offset)
	req.Var("limit", params.Limit)
	req.Var("order_by", params.OrderBy)
	req.Var("order_direction", params.OrderDirection)
	req.Var("filter_asset_state", params.FilterAssetState)

	var res struct {
		AllAssets *AssetsResult `json:"allAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssets, nil
}

func (c *Client) GetAllAssets(params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetAllAssetsCtx(context.Background(), params, opts...)
}

func (c *Client) GetAllAssetsExportCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int) {
		allAssetsExport(offset: $offset, limit: $limit) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AllAssetsExport *AssetsResult `json:"allAssetsExport"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssetsExport, nil
}

func (c *Client) GetAllAssetsExport(offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetAllAssetsExportCtx(context.Background(), offset, limit, opts...)
}

func (c *Client) GetAssetCountCtx(ctx context.Context, endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error) {
	req := graphql.NewRequest(`query($endpoint_type: AgentType) {
		assetCount(endpoint_type: $endpoint_type) {`+allAssetCountsFields+`
		}
	}`, opts...)
	req.Var("endpoint_type", endpoint_type)

	var res struct {
		AssetCount AssetCounts `json:"assetCount"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return AssetCounts{}, err
	}

	return res.AssetCount, nil
}

func (c *Client) GetAssetCount(endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error) {
	return c.GetAssetCountCtx(context.Background(), endpoint_type, opts...)
}

func (c *Client) GetAssetCountGroupByEndpointTypeCtx(ctx context.Context, opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error) {
	req := graphql.NewRequest(`query {
		assetCountGroupByEndpointType {`+allAssetCountsByEndpointTypeFields+`
		}
	}`, opts...)

	var res struct {
		AssetCountGroupByEndpointType []*AssetCountsByEndpointType `json:"assetCountGroupByEndpointType"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetCountGroupByEndpointType, nil
}

func (c *Client) GetAssetCountGroupByEndpointType(opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error) {
	return c.GetAssetCountGroupByEndpointTypeCtx(context.Background(), opts...)
}

func (c *Client) GetAllAssetsCountCtx(ctx context.Context, opts ...graphql.RequestOption) (AssetCounts, error) {
	req := graphql.NewRequest(`query {
		allAssetsCount {`+allAssetCountsFields+`
		}
	}`, opts...)

	var res struct {
		AllAssetsCount AssetCounts `json:"allAssetsCount"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return AssetCounts{}, err
	}

	return res.AllAssetsCount, nil
}

func (c *Client) GetAllAssetsCount(opts ...graphql.RequestOption) (AssetCounts, error) {
	return c.GetAllAssetsCountCtx(context.Background(), opts...)
}

func (c *Client) GetAssetsByIdsCtx(ctx context.Context, ids []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($ids: [ID!]) {
		assetsByIds(ids: $ids) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("ids", ids)

	var res struct {
		AssetsByIds []*Asset `json:"assetsByIds"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByIds, nil
}

func (c *Client) GetAssetsByIds(ids []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByIdsCtx(context.Background(), ids, opts...)
}

func (c *Client) GetAssetsByHostIdsCtx(ctx context.Context, hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($hostIds: [String!]) {
		assetsByHostIds(hostIds: $hostIds) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("hostIds", hostIds)

	var res struct {
		AssetsByHostIds []*Asset `json:"assetsByHostIds"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByHostIds, nil
}

func (c *Client) GetAssetsByHostIds(hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByHostIdsCtx(context.Background(), hostIds, opts...)
}

func (c *Client) GetAssetsByIpAddressesCtx(ctx context.Context, ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($ipAddresses: [String!]) {
		assetsByIpAddresses(ipAddresses: $ipAddresses) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("ipAddresses", ipAddresses)

	var res struct {
		AssetsByIpAddresses []*Asset `json:"assetsByIpAddresses"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByIpAddresses, nil
}

func (c *Client) GetAssetsByIpAddresses(ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByIpAddressesCtx(context.Background(), ipAddresses, opts...)
}

func (c *Client) GetAllAssetHistoriesCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int) {
		allAssetHistories(offset: $offset, limit: $limit) {`+allAssetHistoryFields+`
		}
	}`, opts...)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AllAssetHistories []*AssetHistory `json:"allAssetHistories"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssetHistories, nil
}

func (c *Client) GetAllAssetHistories(offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error) {
	return c.GetAllAssetHistoriesCtx(context.Background(), offset, limit, opts...)
}

func (c *Client) GetAssetRedCloakHistoriesCtx(ctx context.Context, id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error) {
	req := graphql.NewRequest(`query($id: ID!, $offset: Int, $limit: Int) {
		assetRedCloakHistories(id: $id, offset: $offset, limit: $limit) {`+allAssetRedCloakHistoryFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AssetRedCloakHistories []*AssetRedCloakHistory `json:"assetRedCloakHistories"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetRedCloakHistories, nil
}

func (c *Client) GetAssetRedCloakHistories(id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error) {
	return c.GetAssetRedCloakHistoriesCtx(context.Background(), id, offset, limit, opts...)
}

type GetSearchAssetsArguments struct {
	Offset             *int                       `json:"offset"`
	Limit              *int                       `json:"limit"`
	Hostname           *string                    `json:"hostname"`
	HostId             *string                    `json:"host_id"`
	IpAddress          *string                    `json:"ip_address"`
	MacAddress         *string                    `json:"mac_address"`
	OsVersion          *string                    `json:"os_version"`
	OsFamily           *string                    `json:"os_family"`
	OsDistributor      *string                    `json:"os_distributor"`
	Username           *string                    `json:"username"`
	EndpointType       *string                    `json:"endpoint_type"`
	Tag                *string                    `json:"tag"`
	HostIdPartialMatch *bool                      `json:"host_id_partial_match"`
	OnlyMostRecent     *bool                      `json:"only_most_recent"`
	OrderBy            *AssetsOrderByInput        `json:"order_by"`
	OrderDirection     *AssetsOrderDirectionInput `json:"order_direction"`
	OrSearch           *bool                      `json:"or_search"`
	FilterAssetState   *AssetStateFilter          `json:"filter_asset_state"`
}

func (c *Client) GetSearchAssetsCtx(ctx context.Context, params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int, $hostname: String, $host_id: String, $ip_address: String, $mac_address: String, $os_version: String, $os_family: String, $os_distributor: String, $username: String, $endpoint_type: String, $tag: String, $host_id_partial_match: Boolean, $only_most_recent: Boolean, $order_by: AssetsOrderByInput, $order_direction: AssetsOrderDirectionInput, $or_search: Boolean, $filter_asset_state: AssetStateFilter) {
		searchAssets(offset: $offset, limit: $limit, hostname: $hostname, host_id: $host_id, ip_address: $ip_address, mac_address: $mac_address, os_version: $os_version, os_family: $os_family, os_distributor: $os_distributor, username: $username, endpoint_type: $endpoint_type, tag: $tag, host_id_partial_match: $host_id_partial_match, only_most_recent: $only_most_recent, order_by: $order_by, order_direction: $order_direction, or_search: $or_search, filter_asset_state: $filter_asset_state) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", params.Offset)
	req.Var("limit", params.Limit)
	req.Var("hostname", params.Hostname)
	req.Var("host_id", params.HostId)
	req.Var("ip_address", params.IpAddress)
	req.Var("mac_address", params.MacAddress)
	req.Var("os_version", params.OsVersion)
	req.Var("os_family", params.OsFamily)
	req.Var("os_distributor", params.OsDistributor)
	req.Var("username", params.Username)
	req.Var("endpoint_type", params.EndpointType)
	req.Var("tag", params.Tag)
	req.Var("host_id_partial_match", params.HostIdPartialMatch)
	req.Var("only_most_recent", params.OnlyMostRecent)
	req.Var("order_by", params.OrderBy)
	req.Var("order_direction", params.OrderDirection)
	req.Var("or_search", params.OrSearch)
	req.Var("filter_asset_state", params.FilterAssetState)

	var res struct {
		SearchAssets *AssetsResult `json:"searchAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.SearchAssets, nil
}

func (c *Client) GetSearchAssets(params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetSearchAssetsCtx(context.Background(), params, opts...)
}

func (c *Client) GetSearchAssetsV2Ctx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($input: SearchAssetsInput!, $paginationInput: SearchAssetsPaginationInput) {
		searchAssetsV2(input: $input, paginationInput: $paginationInput) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("input", input)
	req.Var("paginationInput", paginationInput)

	var res struct {
		SearchAssetsV2 *AssetsResult `json:"searchAssetsV2"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.SearchAssetsV2, nil
}

func (c *Client) GetSearchAssetsV2(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetSearchAssetsV2Ctx(context.Background(), input, paginationInput, opts...)
}

func (c *Client) GetExportSearchAssetsCtx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error) {
	req := graphql.NewRequest(`query($input: SearchAssetsInput!, $paginationInput: SearchAssetsPaginationInput) {
		exportSearchAssets(input: $input, paginationInput: $paginationInput) {`+allAssetsExportOutputFields+`
		}
	}`, opts...)
	req.Var("input", input)
	req.Var("paginationInput", paginationInput)

	var res struct {
		ExportSearchAssets *AssetsExportOutput `json:"exportSearchAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.ExportSearchAssets, nil
}

func (c *Client) GetExportSearchAssets(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error) {
	return c.GetExportSearchAssetsCtx(context.Background(), input, paginationInput, opts...)
}

func (c *Client) IsolateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $reason: String!) {
		isolateAsset(id: $id, reason: $reason) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("reason", reason)

	var res struct {
		IsolateAsset Asset `json:"isolateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.IsolateAsset, nil
}

func (c *Client) IsolateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	return c.IsolateAssetCtx(context.Background(), id, reason, opts...)
}

func (c *Client) IntegrateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $reason: String!) {
		integrateAsset(id: $id, reason: $reason) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("reason", reason)

	var res struct {
		IntegrateAsset Asset `json:"integrateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.IntegrateAsset, nil
}

func (c *Client) IntegrateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	return c.IntegrateAssetCtx(context.Background(), id, reason, opts...)
}

func (c *Client) DeleteAssetsCtx(ctx context.Context, ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error) {
	req := graphql.NewRequest(`mutation($ids: [ID!]!, $undelete: Boolean) {
		deleteAssets(ids: $ids, undelete: $undelete)
	}`, opts...)
	req.Var("ids", ids)
	req.Var("undelete", undelete)

	var res struct {
		DeleteAssets *bool `json:"deleteAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.DeleteAssets, nil
}

func (c *Client) DeleteAssets(ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error) {
	return c.DeleteAssetsCtx(context.Background(), ids, undelete, opts...)
}

func (c *Client) CreateAssetTagCtx(ctx context.Context, hostId string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`mutation($hostId: String!, $tag: String!) {
		createAssetTag(hostId: $hostId, tag: $tag) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("hostId", hostId)
	req.Var("tag", tag)

	var res struct {
		CreateAssetTag Tag `json:"createAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.CreateAssetTag, nil
}

func (c *Client) CreateAssetTag(hostId string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	return c.CreateAssetTagCtx(context.Background(), hostId, tag, opts...)
}

func (c *Client) UpdateAssetTagCtx(ctx context.Context, id string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $tag: String!) {
		updateAssetTag(id: $id, tag: $tag) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("tag", tag)

	var res struct {
		UpdateAssetTag Tag `json:"updateAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.UpdateAssetTag, nil
}

func (c *Client) UpdateAssetTag(id string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	return c.UpdateAssetTagCtx(context.Background(), id, tag, opts...)
}

func (c *Client) DeleteAssetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (*Tag, error) {
	req := graphql.NewRequest(`mutation($id: ID!) {
		deleteAssetTag(id: $id) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		DeleteAssetTag *Tag `json:"deleteAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.DeleteAssetTag, nil
}

func (c *Client) DeleteAssetTag(id string, opts ...graphql.RequestOption) (*Tag, error) {
	return c.DeleteAssetTagCtx(context.Background(), id, opts...)
}

func (c *Client) UpdateAssetCtx(ctx context.Context, assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($assetInput: AssetInput) {
		updateAsset(assetInput: $assetInput) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("assetInput", assetInput)

	var res struct {
		UpdateAsset Asset `json:"updateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.UpdateAsset, nil
}

func (c *Client) UpdateAsset(assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error) {
	return c.UpdateAssetCtx(context.Background(), assetInput, opts...)
}

type IClient interface {
	GetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Tag, error)
	GetTag(id string, opts ...graphql.RequestOption) (Tag, error)
	GetAssetCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Asset, error)
	GetAsset(id string, opts ...graphql.RequestOption) (Asset, error)
	GetAssetsByTagCtx(ctx context.Context, tags []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByTag(tags []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAllUniqueTagsCtx(ctx context.Context, opts ...graphql.RequestOption) ([]string, error)
	GetAllUniqueTags(opts ...graphql.RequestOption) ([]string, error)
	GetAssetEndpointInfoCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (EndpointInfo, error)
	GetAssetEndpointInfo(id string, opts ...graphql.RequestOption) (EndpointInfo, error)
	GetAllAssetsCtx(ctx context.Context, params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssets(params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssetsExportCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssetsExport(offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAssetCountCtx(ctx context.Context, endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetCount(endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetCountGroupByEndpointTypeCtx(ctx context.Context, opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error)
	GetAssetCountGroupByEndpointType(opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error)
	GetAllAssetsCountCtx(ctx context.Context, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAllAssetsCount(opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetsByIdsCtx(ctx context.Context, ids []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIds(ids []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByHostIdsCtx(ctx context.Context, hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByHostIds(hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIpAddressesCtx(ctx context.Context, ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIpAddresses(ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAllAssetHistoriesCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error)
	GetAllAssetHistories(offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error)
	GetAssetRedCloakHistoriesCtx(ctx context.Context, id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error)
	GetAssetRedCloakHistories(id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error)
	GetSearchAssetsCtx(ctx context.Context, params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssets(params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssetsV2Ctx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssetsV2(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetExportSearchAssetsCtx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error)
	GetExportSearchAssets(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error)
	IsolateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IsolateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IntegrateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IntegrateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	DeleteAssetsCtx(ctx context.Context, ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error)
	DeleteAssets(ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error)
	CreateAssetTagCtx(ctx context.Context, hostId string, tag string, opts ...graphql.RequestOption) (Tag, error)
	CreateAssetTag(hostId string, tag string, opts ...graphql.RequestOption) (Tag, error)
	UpdateAssetTagCtx(ctx context.Context, id string, tag string, opts ...graphql.RequestOption) (Tag, error)
	UpdateAssetTag(id string, tag string, opts ...graphql.RequestOption) (Tag, error)
	DeleteAssetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (*Tag, error)
	DeleteAssetTag(id string, opts ...graphql.RequestOption) (*Tag, error)
	UpdateAssetCtx(ctx context.Context, assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error)
	UpdateAsset(assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error)
}

var _ IClient = (*Client)(nil)
// Code generated by gql_clientgen, please do not edit

package assets

import (
	"github.com/secureworks/taegis-sdk-go/client"
	"github.com/secureworks/taegis-sdk-go/graphql"
	"context"
	"net/http"
	"time"
)

// Client provides an easy to use Go client to the Assets API
type Client struct {
	client *client.Client
	url    string
}

// New returns a new Client, ready for use
func New(url string, opts ...client.Option) *Client {
	client := client.NewClient(opts...)
	return &Client{
		client: client,
		url:    url,
	}
}

func (c *Client) makeRequest(ctx context.Context, req *graphql.Request, res interface{}) error {
	header := http.Header{}
	return graphql.ExecuteQueryContext(ctx, &graphql.QueryConfig{
		HClient:   c.client,
		Header:    header,
		Output:    res,
		Request:   req,
		ServerURL: c.url,
	})
}

const allAssetFields = `
	id
	hostId
	rn
	tenantId
	sensorTenant
	sensorId
	ingestTime
	createdAt
	updatedAt
	deletedAt
	biosSerial
	firstDiskSerial
	systemVolumeSerial
	sensorVersion
	endpointType
	endpointPlatform
	hostnames {` + allHostnameFields + `
	}
	ethernetAddresses {` + allEthernetAddressFields + `
	}
	ipAddresses {` + allIpAddressFields + `
	}
	users {` + allUserFields + `
	}
	architecture
	osFamily
	osVersion
	osDistributor
	osRelease
	systemType
	osCodename
	kernelRelease
	kernelVersion
	tags {` + allTagFields + `
	}
`

const allAssetCountsFields = `
	count
`

const allAssetCountsByEndpointTypeFields = `
	endpointType
	count
`

const allAssetHistoryFields = `
	id
	createdAt
	updatedAt
	assetId
	tenantId
	hostId
	action
	who
	reason
`

const allAssetHistoryContactFields = `
	email
	name
	sub
`

const allAssetHistoryEventFields = `
	domainName
	hostName
`

const allAssetHistoryIdFields = `
	hostId
	instanceId
`

const allAssetRedCloakHistoryFields = `
	action
	allowedDomain
	assetId
	contact {` + allAssetHistoryContactFields + `
	}
	createdAt
	event {` + allAssetHistoryEventFields + `
	}
	id {` + allAssetHistoryIdFields + `
	}
	reason
	tenantId
`

const allAssetsExportOutputFields = `
	columnDef
	rows
	totalCount
`

const allAssetsResultFields = `
	totalResults
	offset
	limit
	assets {` + allAssetFields + `
	}
`

const allEndpointInfoFields = `
	actualIsolationStatus
	allowedDomain
	color
	desiredIsolationStatus
	firstConnectTime
	hostId
	hostName
	ignitionDetails {` + allIgnitionDetailsFields + `
	}
	lastConnectAddress
	lastConnectServer
	lastConnectTime
	lastCrashCheck
	lastModuleStatusTime
	lastPredicateAuthtap
	lastPredicateCyclorama
	lastPredicateEntwine
	lastPredicateGroundling
	lastPredicateHostel
	lastPredicateLacuna
	lastPredicateMukluk
	lastPredicatePeriodicscanControl
	lastPredicatePeriodicscanResult
	lastPredicateProcwall
	lastPredicateSystemInformation
	moduleHealth {` + allModuleHealthFields + `
	}
	moduleStatus {` + allModuleStatusFields + `
	}
	notableEventCount
	sensorVersion
	systemInformation {` + allSystemInformationFields + `
	}
`

const allEthernetAddressFields = `
	id
	createdAt
	updatedAt
	hostId
	mac
`

const allHostnameFields = `
	id
	createdAt
	updatedAt
	hostId
	hostname
`

const allIgnitionDetailsFields = `
	isEndpointConfigExist
	requestStatus
`

const allIpAddressFields = `
	id
	createdAt
	updatedAt
	ip
	hostId
`

const allModuleHealthFields = `
	enabled
	lastPredicateTime
	lastRunningTime
	moduleColor
	moduleDisplayName
`

const allModuleStatusFields = `
	enabled
	moduleName
	moduleState
`

const allSystemInformationFields = `
	architecture
	biosSerial
	ethernetAddress
	firstDiskSerial
	hostName
	ipAddress
	isServerR2For2003And2008
	productType
	redcloakVersion
	servicePack
	systemVolumeSerial
	windowsVersion
`

const allTagFields = `
	id
	hostId
	tenantId
	createdAt
	updatedAt
	tag
`

const allUpdateTagFields = `
	id
	tenantId
	tag
`

const allUserFields = `
	id
	createdAt
	updatedAt
	hostId
	username
`

// Type of Red Cloak endpoint agent.
type AgentType string

const (
	AgentTypeEndpointRedcloak       AgentType = "ENDPOINT_REDCLOAK"
	AgentTypeEndpointCarbonBlack    AgentType = "ENDPOINT_CARBON_BLACK"
	AgentTypeEndpointCrowdStrike    AgentType = "ENDPOINT_CROWD_STRIKE"
	AgentTypeEndpointMicrosoftAtp   AgentType = "ENDPOINT_MICROSOFT_ATP"
	AgentTypeEndpointCarbonBlackPsc AgentType = "ENDPOINT_CARBON_BLACK_PSC"
)

// Describes an Asset in Red Cloak Taegis.
type Asset struct {
	ID                 string            `json:"id"`
	HostId             string            `json:"hostId"`
	Rn                 string            `json:"rn"`
	TenantId           string            `json:"tenantId"`
	SensorTenant       string            `json:"sensorTenant"`
	SensorId           string            `json:"sensorId"`
	IngestTime         time.Time         `json:"ingestTime"`
	CreatedAt          time.Time         `json:"createdAt"`
	UpdatedAt          time.Time         `json:"updatedAt"`
	DeletedAt          *time.Time        `json:"deletedAt"`
	BiosSerial         *string           `json:"biosSerial"`
	FirstDiskSerial    *string           `json:"firstDiskSerial"`
	SystemVolumeSerial *string           `json:"systemVolumeSerial"`
	SensorVersion      *string           `json:"sensorVersion"`
	EndpointType       *string           `json:"endpointType"`
	EndpointPlatform   *string           `json:"endpointPlatform"`
	Hostnames          []Hostname        `json:"hostnames"`
	EthernetAddresses  []EthernetAddress `json:"ethernetAddresses"`
	IpAddresses        []IpAddress       `json:"ipAddresses"`
	Users              []User            `json:"users"`
	Architecture       *string           `json:"architecture"`
	OsFamily           *string           `json:"osFamily"`
	OsVersion          *string           `json:"osVersion"`
	OsDistributor      *string           `json:"osDistributor"`
	OsRelease          *string           `json:"osRelease"`
	SystemType         *string           `json:"systemType"`
	OsCodename         *string           `json:"osCodename"`
	KernelRelease      *string           `json:"kernelRelease"`
	KernelVersion      *string           `json:"kernelVersion"`
	Tags               []Tag             `json:"tags"`
}

// Count of assets
type AssetCounts struct {
	Count int `json:"count"`
}

type AssetCountsByEndpointType struct {
	EndpointType string `json:"endpointType"`
	Count        int    `json:"count"`
}

// Describes the history of an asset.
type AssetHistory struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	AssetId   string    `json:"assetId"`
	TenantId  string    `json:"tenantId"`
	HostId    string    `json:"hostId"`
	Action    string    `json:"action"`
	Who       string    `json:"who"`
	Reason    string    `json:"reason"`
}

// Describes the contact of an asset history.
type AssetHistoryContact struct {
	Email *string `json:"email"`
	Name  *string `json:"name"`
	Sub   *string `json:"sub"`
}

// Describes the event of an asset history.
type AssetHistoryEvent struct {
	DomainName *string `json:"domainName"`
	HostName   *string `json:"hostName"`
}

// Contains the host id and instance id of an asset history.
type AssetHistoryId struct {
	HostId     *string `json:"hostId"`
	InstanceId *string `json:"instanceId"`
}

// Describes the input of Asset data for creating an Asset Tag
type AssetInput struct {
	ID   string   `json:"id"`
	Tags []string `json:"tags"`
}

// Describes the Red Cloak agent history of an asset.
type AssetRedCloakHistory struct {
	Action        *string              `json:"action"`
	AllowedDomain []string             `json:"allowedDomain"`
	AssetId       *string              `json:"assetId"`
	Contact       *AssetHistoryContact `json:"contact"`
	CreatedAt     *string              `json:"createdAt"`
	Event         *AssetHistoryEvent   `json:"event"`
	ID            *AssetHistoryId      `json:"id"`
	Reason        *string              `json:"reason"`
	TenantId      *string              `json:"tenantId"`
}

type AssetStateFilter string

const (
	AssetStateFilterAll       AssetStateFilter = "All"
	AssetStateFilterDeleted   AssetStateFilter = "Deleted"
	AssetStateFilterActive    AssetStateFilter = "Active"
	AssetStateFilterUnhealthy AssetStateFilter = "Unhealthy"
)

type AssetsExportOutput struct {
	ColumnDef  []string `json:"columnDef"`
	Rows       []string `json:"rows"`
	TotalCount *int     `json:"totalCount"`
}

// Describes the enums available for the ordering of the <code>AllAssets</code> and <code>SearchAssets</code> queries.
type AssetsOrderByInput string

const (
	AssetsOrderByInputHostname      AssetsOrderByInput = "hostname"
	AssetsOrderByInputIpAddress     AssetsOrderByInput = "ip_address"
	AssetsOrderByInputMacAddress    AssetsOrderByInput = "mac_address"
	AssetsOrderByInputTag           AssetsOrderByInput = "tag"
	AssetsOrderByInputUsername      AssetsOrderByInput = "username"
	AssetsOrderByInputOsVersion     AssetsOrderByInput = "os_version"
	AssetsOrderByInputEndpointType  AssetsOrderByInput = "endpoint_type"
	AssetsOrderByInputCreatedAt     AssetsOrderByInput = "created_at"
	AssetsOrderByInputUpdatedAt     AssetsOrderByInput = "updated_at"
	AssetsOrderByInputDeletedAt     AssetsOrderByInput = "deleted_at"
	AssetsOrderByInputOsFamily      AssetsOrderByInput = "os_family"
	AssetsOrderByInputOsDistributor AssetsOrderByInput = "os_distributor"
)

// Describes the order direction available for the order field of the <code>AllAssets</code> and <code>SearchAssets</code> queries.
type AssetsOrderDirectionInput string

const (
	AssetsOrderDirectionInputAsc  AssetsOrderDirectionInput = "asc"
	AssetsOrderDirectionInputDesc AssetsOrderDirectionInput = "desc"
)

// Describes the return type of the <code>AllAssets</code> and <code>SearchAssets</code> queries.
type AssetsResult struct {
	TotalResults int     `json:"totalResults"`
	Offset       int     `json:"offset"`
	Limit        int     `json:"limit"`
	Assets       []Asset `json:"assets"`
}

// Describes the endpoint information of a Red Cloak agent asset.
type EndpointInfo struct {
	ActualIsolationStatus            *bool              `json:"actualIsolationStatus"`
	AllowedDomain                    []string           `json:"allowedDomain"`
	Color                            *string            `json:"color"`
	DesiredIsolationStatus           *bool              `json:"desiredIsolationStatus"`
	FirstConnectTime                 *string            `json:"firstConnectTime"`
	HostId                           *string            `json:"hostId"`
	HostName                         *string            `json:"hostName"`
	IgnitionDetails                  *IgnitionDetails   `json:"ignitionDetails"`
	LastConnectAddress               *string            `json:"lastConnectAddress"`
	LastConnectServer                *string            `json:"lastConnectServer"`
	LastConnectTime                  *string            `json:"lastConnectTime"`
	LastCrashCheck                   *string            `json:"lastCrashCheck"`
	LastModuleStatusTime             *string            `json:"lastModuleStatusTime"`
	LastPredicateAuthtap             *string            `json:"lastPredicateAuthtap"`
	LastPredicateCyclorama           *string            `json:"lastPredicateCyclorama"`
	LastPredicateEntwine             *string            `json:"lastPredicateEntwine"`
	LastPredicateGroundling          *string            `json:"lastPredicateGroundling"`
	LastPredicateHostel              *string            `json:"lastPredicateHostel"`
	LastPredicateLacuna              *string            `json:"lastPredicateLacuna"`
	LastPredicateMukluk              *string            `json:"lastPredicateMukluk"`
	LastPredicatePeriodicscanControl *string            `json:"lastPredicatePeriodicscanControl"`
	LastPredicatePeriodicscanResult  *string            `json:"lastPredicatePeriodicscanResult"`
	LastPredicateProcwall            *string            `json:"lastPredicateProcwall"`
	LastPredicateSystemInformation   *string            `json:"lastPredicateSystemInformation"`
	ModuleHealth                     []ModuleHealth     `json:"moduleHealth"`
	ModuleStatus                     []ModuleStatus     `json:"moduleStatus"`
	NotableEventCount                *int               `json:"notableEventCount"`
	SensorVersion                    *int               `json:"sensorVersion"`
	SystemInformation                *SystemInformation `json:"systemInformation"`
}

// Describes the ethernet address of an asset.
type EthernetAddress struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Mac       string    `json:"mac"`
}

// Describes the hostname of an asset.
type Hostname struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Hostname  string    `json:"hostname"`
}

// Describes the ignition details of a Red Cloak agent asset.
type IgnitionDetails struct {
	IsEndpointConfigExist *bool   `json:"isEndpointConfigExist"`
	RequestStatus         *string `json:"requestStatus"`
}

// Describes the IP Address of an asset.
type IpAddress struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	Ip        string    `json:"ip"`
	HostId    string    `json:"hostId"`
}

// Describes the ModuleHealth of a Red Cloak agent asset.
type ModuleHealth struct {
	Enabled           *string `json:"enabled"`
	LastPredicateTime *string `json:"lastPredicateTime"`
	LastRunningTime   *string `json:"lastRunningTime"`
	ModuleColor       *string `json:"moduleColor"`
	ModuleDisplayName *string `json:"moduleDisplayName"`
}

// Describes the module status of a Red Cloak agent asset.
type ModuleStatus struct {
	Enabled     *bool   `json:"enabled"`
	ModuleName  *string `json:"moduleName"`
	ModuleState *string `json:"moduleState"`
}

type SearchAssetsInput struct {
	Hostname           *string           `json:"hostname"`
	HostId             *string           `json:"host_id"`
	IpAddress          *string           `json:"ip_address"`
	MacAddress         *string           `json:"mac_address"`
	OsVersion          *string           `json:"os_version"`
	OsFamily           *string           `json:"os_family"`
	OsDistributor      *string           `json:"os_distributor"`
	Username           *string           `json:"username"`
	EndpointType       *string           `json:"endpoint_type"`
	Tag                *string           `json:"tag"`
	HostIdPartialMatch *bool             `json:"host_id_partial_match"`
	OnlyMostRecent     *bool             `json:"only_most_recent"`
	OrSearch           *bool             `json:"or_search"`
	FilterAssetState   *AssetStateFilter `json:"filter_asset_state"`
}

type SearchAssetsPaginationInput struct {
	Offset         *int                       `json:"offset"`
	Limit          *int                       `json:"limit"`
	OrderBy        *AssetsOrderByInput        `json:"order_by"`
	OrderDirection *AssetsOrderDirectionInput `json:"order_direction"`
}

// Describes the system information of a Red Cloak agent asset.
type SystemInformation struct {
	Architecture             *string  `json:"architecture"`
	BiosSerial               *string  `json:"biosSerial"`
	EthernetAddress          []string `json:"ethernetAddress"`
	FirstDiskSerial          *string  `json:"firstDiskSerial"`
	HostName                 *string  `json:"hostName"`
	IpAddress                []string `json:"ipAddress"`
	IsServerR2For2003And2008 *bool    `json:"isServerR2For2003And2008"`
	ProductType              *string  `json:"productType"`
	RedcloakVersion          *int     `json:"redcloakVersion"`
	ServicePack              *string  `json:"servicePack"`
	SystemVolumeSerial       *string  `json:"systemVolumeSerial"`
	WindowsVersion           *string  `json:"windowsVersion"`
}

// Describes the tag data associated with an asset
type Tag struct {
	ID        string    `json:"id"`
	HostId    string    `json:"hostId"`
	TenantId  string    `json:"tenantId"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	Tag       string    `json:"tag"`
}

// Describes the tag data associated with an asset
type UpdateTag struct {
	ID       string `json:"id"`
	TenantId string `json:"tenantId"`
	Tag      string `json:"tag"`
}

// Describes the user of an asset.
type User struct {
	ID        string    `json:"id"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	HostId    string    `json:"hostId"`
	Username  string    `json:"username"`
}

// GetTagCtx will gen an asset tag by id
func (c *Client) GetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		tag(id: $id) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		Tag Tag `json:"tag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.Tag, nil
}

// GetTag will gen an asset tag by id
func (c *Client) GetTag(id string, opts ...graphql.RequestOption) (Tag, error) {
	return c.GetTagCtx(context.Background(), id, opts...)
}

// GetAssetCtx will get an asset by id
func (c *Client) GetAssetCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		asset(id: $id) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		Asset Asset `json:"asset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.Asset, nil
}

// GetAsset will get an asset by id
func (c *Client) GetAsset(id string, opts ...graphql.RequestOption) (Asset, error) {
	return c.GetAssetCtx(context.Background(), id, opts...)
}

// GetAssetsByTagCtx will get a list of assets with tag
func (c *Client) GetAssetsByTagCtx(ctx context.Context, tags []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($tags: [String!]!) {
		assetsByTag(tags: $tags) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("tags", tags)

	var res struct {
		AssetsByTag []*Asset `json:"assetsByTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByTag, nil
}

// GetAssetsByTag will get a list of assets with tag
func (c *Client) GetAssetsByTag(tags []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByTagCtx(context.Background(), tags, opts...)
}

// GetAllUniqueTagsCtx will get a list of all unique tags
func (c *Client) GetAllUniqueTagsCtx(ctx context.Context, opts ...graphql.RequestOption) ([]string, error) {
	req := graphql.NewRequest(`query {
		allUniqueTags
	}`, opts...)

	var res struct {
		AllUniqueTags []string `json:"allUniqueTags"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllUniqueTags, nil
}

// GetAllUniqueTags will get a list of all unique tags
func (c *Client) GetAllUniqueTags(opts ...graphql.RequestOption) ([]string, error) {
	return c.GetAllUniqueTagsCtx(context.Background(), opts...)
}

// GetAssetEndpointInfoCtx will get RedCloak endpoint info by id
func (c *Client) GetAssetEndpointInfoCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (EndpointInfo, error) {
	req := graphql.NewRequest(`query($id: ID!) {
		assetEndpointInfo(id: $id) {`+allEndpointInfoFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		AssetEndpointInfo EndpointInfo `json:"assetEndpointInfo"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return EndpointInfo{}, err
	}

	return res.AssetEndpointInfo, nil
}

// GetAssetEndpointInfo will get RedCloak endpoint info by id
func (c *Client) GetAssetEndpointInfo(id string, opts ...graphql.RequestOption) (EndpointInfo, error) {
	return c.GetAssetEndpointInfoCtx(context.Background(), id, opts...)
}

// GetAllAssetsArguments is the parameters for GetAllAssets
type GetAllAssetsArguments struct {
	Offset           *int                       `json:"offset"`
	Limit            *int                       `json:"limit"`
	OrderBy          *AssetsOrderByInput        `json:"order_by"`
	OrderDirection   *AssetsOrderDirectionInput `json:"order_direction"`
	FilterAssetState *AssetStateFilter          `json:"filter_asset_state"`
}

// GetAllAssetsCtx will get a list of assets
func (c *Client) GetAllAssetsCtx(ctx context.Context, params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int, $order_by: AssetsOrderByInput, $order_direction: AssetsOrderDirectionInput, $filter_asset_state: AssetStateFilter) {
		allAssets(offset: $offset, limit: $limit, order_by: $order_by, order_direction: $order_direction, filter_asset_state: $filter_asset_state) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", params.Offset)
	req.Var("limit", params.Limit)
	req.Var("order_by", params.OrderBy)
	req.Var("order_direction", params.OrderDirection)
	req.Var("filter_asset_state", params.FilterAssetState)

	var res struct {
		AllAssets *AssetsResult `json:"allAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssets, nil
}

// GetAllAssets will get a list of assets
func (c *Client) GetAllAssets(params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetAllAssetsCtx(context.Background(), params, opts...)
}

// GetAllAssetsExportCtx will get a list of assets for export to CSV
func (c *Client) GetAllAssetsExportCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int) {
		allAssetsExport(offset: $offset, limit: $limit) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AllAssetsExport *AssetsResult `json:"allAssetsExport"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssetsExport, nil
}

// GetAllAssetsExport will get a list of assets for export to CSV
func (c *Client) GetAllAssetsExport(offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetAllAssetsExportCtx(context.Background(), offset, limit, opts...)
}

// GetAssetCountCtx will count of assets of a specific endpoint_type
func (c *Client) GetAssetCountCtx(ctx context.Context, endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error) {
	req := graphql.NewRequest(`query($endpoint_type: AgentType) {
		assetCount(endpoint_type: $endpoint_type) {`+allAssetCountsFields+`
		}
	}`, opts...)
	req.Var("endpoint_type", endpoint_type)

	var res struct {
		AssetCount AssetCounts `json:"assetCount"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return AssetCounts{}, err
	}

	return res.AssetCount, nil
}

// GetAssetCount will count of assets of a specific endpoint_type
func (c *Client) GetAssetCount(endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error) {
	return c.GetAssetCountCtx(context.Background(), endpoint_type, opts...)
}

// GetAssetCountGroupByEndpointTypeCtx will count of assets of grouped by endpoint_type
func (c *Client) GetAssetCountGroupByEndpointTypeCtx(ctx context.Context, opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error) {
	req := graphql.NewRequest(`query {
		assetCountGroupByEndpointType {`+allAssetCountsByEndpointTypeFields+`
		}
	}`, opts...)

	var res struct {
		AssetCountGroupByEndpointType []*AssetCountsByEndpointType `json:"assetCountGroupByEndpointType"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetCountGroupByEndpointType, nil
}

// GetAssetCountGroupByEndpointType will count of assets of grouped by endpoint_type
func (c *Client) GetAssetCountGroupByEndpointType(opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error) {
	return c.GetAssetCountGroupByEndpointTypeCtx(context.Background(), opts...)
}

// GetAllAssetsCountCtx will count of all assets
func (c *Client) GetAllAssetsCountCtx(ctx context.Context, opts ...graphql.RequestOption) (AssetCounts, error) {
	req := graphql.NewRequest(`query {
		allAssetsCount {`+allAssetCountsFields+`
		}
	}`, opts...)

	var res struct {
		AllAssetsCount AssetCounts `json:"allAssetsCount"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return AssetCounts{}, err
	}

	return res.AllAssetsCount, nil
}

// GetAllAssetsCount will count of all assets
func (c *Client) GetAllAssetsCount(opts ...graphql.RequestOption) (AssetCounts, error) {
	return c.GetAllAssetsCountCtx(context.Background(), opts...)
}

// GetAssetsByIdsCtx will bulk lookup by ids
func (c *Client) GetAssetsByIdsCtx(ctx context.Context, ids []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($ids: [ID!]) {
		assetsByIds(ids: $ids) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("ids", ids)

	var res struct {
		AssetsByIds []*Asset `json:"assetsByIds"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByIds, nil
}

// GetAssetsByIds will bulk lookup by ids
func (c *Client) GetAssetsByIds(ids []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByIdsCtx(context.Background(), ids, opts...)
}

// GetAssetsByHostIdsCtx will bulk lookup by hostIds
func (c *Client) GetAssetsByHostIdsCtx(ctx context.Context, hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($hostIds: [String!]) {
		assetsByHostIds(hostIds: $hostIds) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("hostIds", hostIds)

	var res struct {
		AssetsByHostIds []*Asset `json:"assetsByHostIds"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByHostIds, nil
}

// GetAssetsByHostIds will bulk lookup by hostIds
func (c *Client) GetAssetsByHostIds(hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByHostIdsCtx(context.Background(), hostIds, opts...)
}

// GetAssetsByIpAddressesCtx will bulk lookup by ipAddress
func (c *Client) GetAssetsByIpAddressesCtx(ctx context.Context, ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	req := graphql.NewRequest(`query($ipAddresses: [String!]) {
		assetsByIpAddresses(ipAddresses: $ipAddresses) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("ipAddresses", ipAddresses)

	var res struct {
		AssetsByIpAddresses []*Asset `json:"assetsByIpAddresses"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetsByIpAddresses, nil
}

// GetAssetsByIpAddresses will bulk lookup by ipAddress
func (c *Client) GetAssetsByIpAddresses(ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error) {
	return c.GetAssetsByIpAddressesCtx(context.Background(), ipAddresses, opts...)
}

// GetAllAssetHistoriesCtx will get a list of asset histories for the tenant
func (c *Client) GetAllAssetHistoriesCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int) {
		allAssetHistories(offset: $offset, limit: $limit) {`+allAssetHistoryFields+`
		}
	}`, opts...)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AllAssetHistories []*AssetHistory `json:"allAssetHistories"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AllAssetHistories, nil
}

// GetAllAssetHistories will get a list of asset histories for the tenant
func (c *Client) GetAllAssetHistories(offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error) {
	return c.GetAllAssetHistoriesCtx(context.Background(), offset, limit, opts...)
}

// GetAssetRedCloakHistoriesCtx will get history of actions on an asset by id (includes RedCloack history)
func (c *Client) GetAssetRedCloakHistoriesCtx(ctx context.Context, id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error) {
	req := graphql.NewRequest(`query($id: ID!, $offset: Int, $limit: Int) {
		assetRedCloakHistories(id: $id, offset: $offset, limit: $limit) {`+allAssetRedCloakHistoryFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("offset", offset)
	req.Var("limit", limit)

	var res struct {
		AssetRedCloakHistories []*AssetRedCloakHistory `json:"assetRedCloakHistories"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.AssetRedCloakHistories, nil
}

// GetAssetRedCloakHistories will get history of actions on an asset by id (includes RedCloack history)
func (c *Client) GetAssetRedCloakHistories(id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error) {
	return c.GetAssetRedCloakHistoriesCtx(context.Background(), id, offset, limit, opts...)
}

// GetSearchAssetsArguments is the parameters for GetSearchAssets
type GetSearchAssetsArguments struct {
	Offset             *int                       `json:"offset"`
	Limit              *int                       `json:"limit"`
	Hostname           *string                    `json:"hostname"`
	HostId             *string                    `json:"host_id"`
	IpAddress          *string                    `json:"ip_address"`
	MacAddress         *string                    `json:"mac_address"`
	OsVersion          *string                    `json:"os_version"`
	OsFamily           *string                    `json:"os_family"`
	OsDistributor      *string                    `json:"os_distributor"`
	Username           *string                    `json:"username"`
	EndpointType       *string                    `json:"endpoint_type"`
	Tag                *string                    `json:"tag"`
	HostIdPartialMatch *bool                      `json:"host_id_partial_match"`
	OnlyMostRecent     *bool                      `json:"only_most_recent"`
	OrderBy            *AssetsOrderByInput        `json:"order_by"`
	OrderDirection     *AssetsOrderDirectionInput `json:"order_direction"`
	OrSearch           *bool                      `json:"or_search"`
	FilterAssetState   *AssetStateFilter          `json:"filter_asset_state"`
}

// GetSearchAssetsCtx will search assets. Soon to be deprecated
func (c *Client) GetSearchAssetsCtx(ctx context.Context, params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($offset: Int, $limit: Int, $hostname: String, $host_id: String, $ip_address: String, $mac_address: String, $os_version: String, $os_family: String, $os_distributor: String, $username: String, $endpoint_type: String, $tag: String, $host_id_partial_match: Boolean, $only_most_recent: Boolean, $order_by: AssetsOrderByInput, $order_direction: AssetsOrderDirectionInput, $or_search: Boolean, $filter_asset_state: AssetStateFilter) {
		searchAssets(offset: $offset, limit: $limit, hostname: $hostname, host_id: $host_id, ip_address: $ip_address, mac_address: $mac_address, os_version: $os_version, os_family: $os_family, os_distributor: $os_distributor, username: $username, endpoint_type: $endpoint_type, tag: $tag, host_id_partial_match: $host_id_partial_match, only_most_recent: $only_most_recent, order_by: $order_by, order_direction: $order_direction, or_search: $or_search, filter_asset_state: $filter_asset_state) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("offset", params.Offset)
	req.Var("limit", params.Limit)
	req.Var("hostname", params.Hostname)
	req.Var("host_id", params.HostId)
	req.Var("ip_address", params.IpAddress)
	req.Var("mac_address", params.MacAddress)
	req.Var("os_version", params.OsVersion)
	req.Var("os_family", params.OsFamily)
	req.Var("os_distributor", params.OsDistributor)
	req.Var("username", params.Username)
	req.Var("endpoint_type", params.EndpointType)
	req.Var("tag", params.Tag)
	req.Var("host_id_partial_match", params.HostIdPartialMatch)
	req.Var("only_most_recent", params.OnlyMostRecent)
	req.Var("order_by", params.OrderBy)
	req.Var("order_direction", params.OrderDirection)
	req.Var("or_search", params.OrSearch)
	req.Var("filter_asset_state", params.FilterAssetState)

	var res struct {
		SearchAssets *AssetsResult `json:"searchAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.SearchAssets, nil
}

// GetSearchAssets will search assets. Soon to be deprecated
func (c *Client) GetSearchAssets(params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetSearchAssetsCtx(context.Background(), params, opts...)
}

// GetSearchAssetsV2Ctx will search assets v2
func (c *Client) GetSearchAssetsV2Ctx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error) {
	req := graphql.NewRequest(`query($input: SearchAssetsInput!, $paginationInput: SearchAssetsPaginationInput) {
		searchAssetsV2(input: $input, paginationInput: $paginationInput) {`+allAssetsResultFields+`
		}
	}`, opts...)
	req.Var("input", input)
	req.Var("paginationInput", paginationInput)

	var res struct {
		SearchAssetsV2 *AssetsResult `json:"searchAssetsV2"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.SearchAssetsV2, nil
}

// GetSearchAssetsV2 will search assets v2
func (c *Client) GetSearchAssetsV2(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error) {
	return c.GetSearchAssetsV2Ctx(context.Background(), input, paginationInput, opts...)
}

// GetExportSearchAssetsCtx will export search assets results
func (c *Client) GetExportSearchAssetsCtx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error) {
	req := graphql.NewRequest(`query($input: SearchAssetsInput!, $paginationInput: SearchAssetsPaginationInput) {
		exportSearchAssets(input: $input, paginationInput: $paginationInput) {`+allAssetsExportOutputFields+`
		}
	}`, opts...)
	req.Var("input", input)
	req.Var("paginationInput", paginationInput)

	var res struct {
		ExportSearchAssets *AssetsExportOutput `json:"exportSearchAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.ExportSearchAssets, nil
}

// GetExportSearchAssets will export search assets results
func (c *Client) GetExportSearchAssets(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error) {
	return c.GetExportSearchAssetsCtx(context.Background(), input, paginationInput, opts...)
}

// IsolateAssetCtx will isolate an asset by id
func (c *Client) IsolateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $reason: String!) {
		isolateAsset(id: $id, reason: $reason) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("reason", reason)

	var res struct {
		IsolateAsset Asset `json:"isolateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.IsolateAsset, nil
}

// IsolateAsset will isolate an asset by id
func (c *Client) IsolateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	return c.IsolateAssetCtx(context.Background(), id, reason, opts...)
}

// IntegrateAssetCtx will integate an asset by id
func (c *Client) IntegrateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $reason: String!) {
		integrateAsset(id: $id, reason: $reason) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("reason", reason)

	var res struct {
		IntegrateAsset Asset `json:"integrateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.IntegrateAsset, nil
}

// IntegrateAsset will integate an asset by id
func (c *Client) IntegrateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error) {
	return c.IntegrateAssetCtx(context.Background(), id, reason, opts...)
}

// DeleteAssetsCtx will delete or un-delete asset
func (c *Client) DeleteAssetsCtx(ctx context.Context, ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error) {
	req := graphql.NewRequest(`mutation($ids: [ID!]!, $undelete: Boolean) {
		deleteAssets(ids: $ids, undelete: $undelete)
	}`, opts...)
	req.Var("ids", ids)
	req.Var("undelete", undelete)

	var res struct {
		DeleteAssets *bool `json:"deleteAssets"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.DeleteAssets, nil
}

// DeleteAssets will delete or un-delete asset
func (c *Client) DeleteAssets(ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error) {
	return c.DeleteAssetsCtx(context.Background(), ids, undelete, opts...)
}

// CreateAssetTagCtx will create a new tag for an asseti
func (c *Client) CreateAssetTagCtx(ctx context.Context, hostId string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`mutation($hostId: String!, $tag: String!) {
		createAssetTag(hostId: $hostId, tag: $tag) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("hostId", hostId)
	req.Var("tag", tag)

	var res struct {
		CreateAssetTag Tag `json:"createAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.CreateAssetTag, nil
}

// CreateAssetTag will create a new tag for an asseti
func (c *Client) CreateAssetTag(hostId string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	return c.CreateAssetTagCtx(context.Background(), hostId, tag, opts...)
}

// UpdateAssetTagCtx will updates a tag for an asset
func (c *Client) UpdateAssetTagCtx(ctx context.Context, id string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	req := graphql.NewRequest(`mutation($id: ID!, $tag: String!) {
		updateAssetTag(id: $id, tag: $tag) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)
	req.Var("tag", tag)

	var res struct {
		UpdateAssetTag Tag `json:"updateAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Tag{}, err
	}

	return res.UpdateAssetTag, nil
}

// UpdateAssetTag will updates a tag for an asset
func (c *Client) UpdateAssetTag(id string, tag string, opts ...graphql.RequestOption) (Tag, error) {
	return c.UpdateAssetTagCtx(context.Background(), id, tag, opts...)
}

// DeleteAssetTagCtx will deletes a tag for an asset
func (c *Client) DeleteAssetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (*Tag, error) {
	req := graphql.NewRequest(`mutation($id: ID!) {
		deleteAssetTag(id: $id) {`+allTagFields+`
		}
	}`, opts...)
	req.Var("id", id)

	var res struct {
		DeleteAssetTag *Tag `json:"deleteAssetTag"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return nil, err
	}

	return res.DeleteAssetTag, nil
}

// DeleteAssetTag will deletes a tag for an asset
func (c *Client) DeleteAssetTag(id string, opts ...graphql.RequestOption) (*Tag, error) {
	return c.DeleteAssetTagCtx(context.Background(), id, opts...)
}

func (c *Client) UpdateAssetCtx(ctx context.Context, assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error) {
	req := graphql.NewRequest(`mutation($assetInput: AssetInput) {
		updateAsset(assetInput: $assetInput) {`+allAssetFields+`
		}
	}`, opts...)
	req.Var("assetInput", assetInput)

	var res struct {
		UpdateAsset Asset `json:"updateAsset"`
	}
	if err := c.makeRequest(ctx, req, &res); err != nil {
		return Asset{}, err
	}

	return res.UpdateAsset, nil
}

func (c *Client) UpdateAsset(assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error) {
	return c.UpdateAssetCtx(context.Background(), assetInput, opts...)
}

// IClient can be used to help mock out the Client in tests
type IClient interface {
	GetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Tag, error)
	GetTag(id string, opts ...graphql.RequestOption) (Tag, error)
	GetAssetCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (Asset, error)
	GetAsset(id string, opts ...graphql.RequestOption) (Asset, error)
	GetAssetsByTagCtx(ctx context.Context, tags []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByTag(tags []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAllUniqueTagsCtx(ctx context.Context, opts ...graphql.RequestOption) ([]string, error)
	GetAllUniqueTags(opts ...graphql.RequestOption) ([]string, error)
	GetAssetEndpointInfoCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (EndpointInfo, error)
	GetAssetEndpointInfo(id string, opts ...graphql.RequestOption) (EndpointInfo, error)
	GetAllAssetsCtx(ctx context.Context, params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssets(params *GetAllAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssetsExportCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAllAssetsExport(offset *int, limit *int, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetAssetCountCtx(ctx context.Context, endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetCount(endpoint_type *AgentType, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetCountGroupByEndpointTypeCtx(ctx context.Context, opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error)
	GetAssetCountGroupByEndpointType(opts ...graphql.RequestOption) ([]*AssetCountsByEndpointType, error)
	GetAllAssetsCountCtx(ctx context.Context, opts ...graphql.RequestOption) (AssetCounts, error)
	GetAllAssetsCount(opts ...graphql.RequestOption) (AssetCounts, error)
	GetAssetsByIdsCtx(ctx context.Context, ids []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIds(ids []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByHostIdsCtx(ctx context.Context, hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByHostIds(hostIds []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIpAddressesCtx(ctx context.Context, ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAssetsByIpAddresses(ipAddresses []string, opts ...graphql.RequestOption) ([]*Asset, error)
	GetAllAssetHistoriesCtx(ctx context.Context, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error)
	GetAllAssetHistories(offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetHistory, error)
	GetAssetRedCloakHistoriesCtx(ctx context.Context, id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error)
	GetAssetRedCloakHistories(id string, offset *int, limit *int, opts ...graphql.RequestOption) ([]*AssetRedCloakHistory, error)
	GetSearchAssetsCtx(ctx context.Context, params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssets(params *GetSearchAssetsArguments, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssetsV2Ctx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetSearchAssetsV2(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsResult, error)
	GetExportSearchAssetsCtx(ctx context.Context, input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error)
	GetExportSearchAssets(input SearchAssetsInput, paginationInput *SearchAssetsPaginationInput, opts ...graphql.RequestOption) (*AssetsExportOutput, error)
	IsolateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IsolateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IntegrateAssetCtx(ctx context.Context, id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	IntegrateAsset(id string, reason string, opts ...graphql.RequestOption) (Asset, error)
	DeleteAssetsCtx(ctx context.Context, ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error)
	DeleteAssets(ids []string, undelete *bool, opts ...graphql.RequestOption) (*bool, error)
	CreateAssetTagCtx(ctx context.Context, hostId string, tag string, opts ...graphql.RequestOption) (Tag, error)
	CreateAssetTag(hostId string, tag string, opts ...graphql.RequestOption) (Tag, error)
	UpdateAssetTagCtx(ctx context.Context, id string, tag string, opts ...graphql.RequestOption) (Tag, error)
	UpdateAssetTag(id string, tag string, opts ...graphql.RequestOption) (Tag, error)
	DeleteAssetTagCtx(ctx context.Context, id string, opts ...graphql.RequestOption) (*Tag, error)
	DeleteAssetTag(id string, opts ...graphql.RequestOption) (*Tag, error)
	UpdateAssetCtx(ctx context.Context, assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error)
	UpdateAsset(assetInput *AssetInput, opts ...graphql.RequestOption) (Asset, error)
}

var _ IClient = (*Client)(nil)
