package presenters

import (
	"time"

	"github.com/lib/pq"
	uuid "github.com/satori/go.uuid"

	"github.com/smartcontractkit/chainlink/core/assets"
	clnull "github.com/smartcontractkit/chainlink/core/null"
	"github.com/smartcontractkit/chainlink/core/services/job"
	"github.com/smartcontractkit/chainlink/core/services/keystore/keys/ethkey"
	"github.com/smartcontractkit/chainlink/core/services/keystore/keys/p2pkey"
	"github.com/smartcontractkit/chainlink/core/services/pipeline"
	"github.com/smartcontractkit/chainlink/core/services/signatures/secp256k1"
	"github.com/smartcontractkit/chainlink/core/store/models"
)

type JobSpecType string

func (t JobSpecType) String() string {
	return string(t)
}

const (
	DirectRequestJobSpec     JobSpecType = "directrequest"
	FluxMonitorJobSpec       JobSpecType = "fluxmonitor"
	OffChainReportingJobSpec JobSpecType = "offchainreporting"
	KeeperJobSpec            JobSpecType = "keeper"
	CronJobSpec              JobSpecType = "cron"
	VRFJobSpec               JobSpecType = "vrf"
	WebhookJobSpec           JobSpecType = "webhook"
)

type DirectRequestSpec struct {
	ContractAddress          ethkey.EIP55Address      `json:"contractAddress"`
	MinIncomingConfirmations clnull.Uint32            `json:"minIncomingConfirmations"`
	MinContractPayment       *assets.Link             `json:"minContractPaymentLinkJuels"`
	Requesters               models.AddressCollection `json:"requesters"`
	Initiator                string                   `json:"initiator"`
	CreatedAt                time.Time                `json:"createdAt"`
	UpdatedAt                time.Time                `json:"updatedAt"`
}

func NewDirectRequestSpec(spec *job.DirectRequestSpec) *DirectRequestSpec {
	return &DirectRequestSpec{
		ContractAddress:          spec.ContractAddress,
		MinIncomingConfirmations: spec.MinIncomingConfirmations,
		MinContractPayment:       spec.MinContractPayment,
		Requesters:               spec.Requesters,

		Initiator: "runlog",
		CreatedAt: spec.CreatedAt,
		UpdatedAt: spec.UpdatedAt,
	}
}

type FluxMonitorSpec struct {
	ContractAddress     ethkey.EIP55Address `json:"contractAddress"`
	Threshold           float32             `json:"threshold"`
	AbsoluteThreshold   float32             `json:"absoluteThreshold"`
	PollTimerPeriod     string              `json:"pollTimerPeriod"`
	PollTimerDisabled   bool                `json:"pollTimerDisabled"`
	IdleTimerPeriod     string              `json:"idleTimerPeriod"`
	IdleTimerDisabled   bool                `json:"idleTimerDisabled"`
	DrumbeatEnabled     bool                `json:"drumbeatEnabled"`
	DrumbeatSchedule    *string             `json:"drumbeatSchedule"`
	DrumbeatRandomDelay *string             `json:"drumbeatRandomDelay"`
	MinPayment          *assets.Link        `json:"minPayment"`
	CreatedAt           time.Time           `json:"createdAt"`
	UpdatedAt           time.Time           `json:"updatedAt"`
}

func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec {
	var drumbeatSchedulePtr *string
	if spec.DrumbeatEnabled {
		drumbeatSchedulePtr = &spec.DrumbeatSchedule
	}
	var drumbeatRandomDelayPtr *string
	if spec.DrumbeatRandomDelay > 0 {
		drumbeatRandomDelay := spec.DrumbeatRandomDelay.String()
		drumbeatRandomDelayPtr = &drumbeatRandomDelay
	}
	return &FluxMonitorSpec{
		ContractAddress:     spec.ContractAddress,
		Threshold:           spec.Threshold,
		AbsoluteThreshold:   spec.AbsoluteThreshold,
		PollTimerPeriod:     spec.PollTimerPeriod.String(),
		PollTimerDisabled:   spec.PollTimerDisabled,
		IdleTimerPeriod:     spec.IdleTimerPeriod.String(),
		IdleTimerDisabled:   spec.IdleTimerDisabled,
		DrumbeatEnabled:     spec.DrumbeatEnabled,
		DrumbeatSchedule:    drumbeatSchedulePtr,
		DrumbeatRandomDelay: drumbeatRandomDelayPtr,
		MinPayment:          spec.MinPayment,
		CreatedAt:           spec.CreatedAt,
		UpdatedAt:           spec.UpdatedAt,
	}
}

type OffChainReportingSpec struct {
	ContractAddress                        ethkey.EIP55Address  `json:"contractAddress"`
	P2PPeerID                              *p2pkey.PeerID       `json:"p2pPeerID"`
	P2PBootstrapPeers                      pq.StringArray       `json:"p2pBootstrapPeers"`
	IsBootstrapPeer                        bool                 `json:"isBootstrapPeer"`
	EncryptedOCRKeyBundleID                *models.Sha256Hash   `json:"keyBundleID"`
	TransmitterAddress                     *ethkey.EIP55Address `json:"transmitterAddress"`
	ObservationTimeout                     models.Interval      `json:"observationTimeout"`
	BlockchainTimeout                      models.Interval      `json:"blockchainTimeout"`
	ContractConfigTrackerSubscribeInterval models.Interval      `json:"contractConfigTrackerSubscribeInterval"`
	ContractConfigTrackerPollInterval      models.Interval      `json:"contractConfigTrackerPollInterval"`
	ContractConfigConfirmations            uint16               `json:"contractConfigConfirmations"`
	CreatedAt                              time.Time            `json:"createdAt"`
	UpdatedAt                              time.Time            `json:"updatedAt"`
}

func NewOffChainReportingSpec(spec *job.OffchainReportingOracleSpec) *OffChainReportingSpec {
	return &OffChainReportingSpec{
		ContractAddress:                        spec.ContractAddress,
		P2PPeerID:                              spec.P2PPeerID,
		P2PBootstrapPeers:                      spec.P2PBootstrapPeers,
		IsBootstrapPeer:                        spec.IsBootstrapPeer,
		EncryptedOCRKeyBundleID:                spec.EncryptedOCRKeyBundleID,
		TransmitterAddress:                     spec.TransmitterAddress,
		ObservationTimeout:                     spec.ObservationTimeout,
		BlockchainTimeout:                      spec.BlockchainTimeout,
		ContractConfigTrackerSubscribeInterval: spec.ContractConfigTrackerSubscribeInterval,
		ContractConfigTrackerPollInterval:      spec.ContractConfigTrackerPollInterval,
		ContractConfigConfirmations:            spec.ContractConfigConfirmations,
		CreatedAt:                              spec.CreatedAt,
		UpdatedAt:                              spec.UpdatedAt,
	}
}

type PipelineSpec struct {
	ID           int32  `json:"id"`
	DotDAGSource string `json:"dotDagSource"`
}

func NewPipelineSpec(spec *pipeline.Spec) PipelineSpec {
	return PipelineSpec{
		ID:           spec.ID,
		DotDAGSource: spec.DotDagSource,
	}
}

type KeeperSpec struct {
	ContractAddress ethkey.EIP55Address `json:"contractAddress"`
	FromAddress     ethkey.EIP55Address `json:"fromAddress"`
	CreatedAt       time.Time           `json:"createdAt"`
	UpdatedAt       time.Time           `json:"updatedAt"`
}

func NewKeeperSpec(spec *job.KeeperSpec) *KeeperSpec {
	return &KeeperSpec{
		ContractAddress: spec.ContractAddress,
		FromAddress:     spec.FromAddress,
		CreatedAt:       spec.CreatedAt,
		UpdatedAt:       spec.UpdatedAt,
	}
}

type WebhookSpec struct {
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

func NewWebhookSpec(spec *job.WebhookSpec) *WebhookSpec {
	return &WebhookSpec{
		CreatedAt: spec.CreatedAt,
		UpdatedAt: spec.UpdatedAt,
	}
}

type CronSpec struct {
	CronSchedule string    `json:"schedule" tom:"schedule"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

func NewCronSpec(spec *job.CronSpec) *CronSpec {
	return &CronSpec{
		CronSchedule: spec.CronSchedule,
		CreatedAt:    spec.CreatedAt,
		UpdatedAt:    spec.UpdatedAt,
	}
}

type VRFSpec struct {
	CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"`
	PublicKey          secp256k1.PublicKey `json:"publicKey"`
	Confirmations      uint32              `json:"confirmations"`
	CreatedAt          time.Time           `json:"createdAt"`
	UpdatedAt          time.Time           `json:"updatedAt"`
}

func NewVRFSpec(spec *job.VRFSpec) *VRFSpec {
	return &VRFSpec{
		CoordinatorAddress: spec.CoordinatorAddress,
		PublicKey:          spec.PublicKey,
		Confirmations:      spec.Confirmations,
		CreatedAt:          spec.CreatedAt,
		UpdatedAt:          spec.UpdatedAt,
	}
}

type JobError struct {
	ID          int64     `json:"id"`
	Description string    `json:"description"`
	Occurrences uint      `json:"occurrences"`
	CreatedAt   time.Time `json:"createdAt"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

func NewJobError(e job.SpecError) JobError {
	return JobError{
		ID:          e.ID,
		Description: e.Description,
		Occurrences: e.Occurrences,
		CreatedAt:   e.CreatedAt,
		UpdatedAt:   e.UpdatedAt,
	}
}

type JobResource struct {
	JAID
	Name                  string                 `json:"name"`
	Type                  JobSpecType            `json:"type"`
	SchemaVersion         uint32                 `json:"schemaVersion"`
	MaxTaskDuration       models.Interval        `json:"maxTaskDuration"`
	ExternalJobID         uuid.UUID              `json:"externalJobID"`
	DirectRequestSpec     *DirectRequestSpec     `json:"directRequestSpec"`
	FluxMonitorSpec       *FluxMonitorSpec       `json:"fluxMonitorSpec"`
	CronSpec              *CronSpec              `json:"cronSpec"`
	OffChainReportingSpec *OffChainReportingSpec `json:"offChainReportingOracleSpec"`
	KeeperSpec            *KeeperSpec            `json:"keeperSpec"`
	VRFSpec               *VRFSpec               `json:"vrfSpec"`
	WebhookSpec           *WebhookSpec           `json:"webhookSpec"`
	PipelineSpec          PipelineSpec           `json:"pipelineSpec"`
	Errors                []JobError             `json:"errors"`
}

func NewJobResource(j job.Job) *JobResource {
	resource := &JobResource{
		JAID:            NewJAIDInt32(j.ID),
		Name:            j.Name.ValueOrZero(),
		Type:            JobSpecType(j.Type),
		SchemaVersion:   j.SchemaVersion,
		MaxTaskDuration: j.MaxTaskDuration,
		PipelineSpec:    NewPipelineSpec(j.PipelineSpec),
		ExternalJobID:   j.ExternalJobID,
	}

	switch j.Type {
	case job.DirectRequest:
		resource.DirectRequestSpec = NewDirectRequestSpec(j.DirectRequestSpec)
	case job.FluxMonitor:
		resource.FluxMonitorSpec = NewFluxMonitorSpec(j.FluxMonitorSpec)
	case job.Cron:
		resource.CronSpec = NewCronSpec(j.CronSpec)
	case job.OffchainReporting:
		resource.OffChainReportingSpec = NewOffChainReportingSpec(j.OffchainreportingOracleSpec)
	case job.Keeper:
		resource.KeeperSpec = NewKeeperSpec(j.KeeperSpec)
	case job.VRF:
		resource.VRFSpec = NewVRFSpec(j.VRFSpec)
	case job.Webhook:
		resource.WebhookSpec = NewWebhookSpec(j.WebhookSpec)
	}

	jes := []JobError{}
	for _, e := range j.JobSpecErrors {
		jes = append(jes, NewJobError((e)))
	}
	resource.Errors = jes

	return resource
}

func NewJobResources(js []job.Job) []JobResource {
	rs := []JobResource{}

	for _, j := range js {
		rs = append(rs, *NewJobResource(j))
	}

	return rs
}

func (r JobResource) GetName() string {
	return "jobs"
}
package presenters

import (
	"time"

	"github.com/lib/pq"
	uuid "github.com/satori/go.uuid"

	"github.com/smartcontractkit/chainlink/core/assets"
	clnull "github.com/smartcontractkit/chainlink/core/null"
	"github.com/smartcontractkit/chainlink/core/services/job"
	"github.com/smartcontractkit/chainlink/core/services/keystore/keys/ethkey"
	"github.com/smartcontractkit/chainlink/core/services/keystore/keys/p2pkey"
	"github.com/smartcontractkit/chainlink/core/services/pipeline"
	"github.com/smartcontractkit/chainlink/core/services/signatures/secp256k1"
	"github.com/smartcontractkit/chainlink/core/store/models"
)

// JobSpecType defines the the the spec type of the job
type JobSpecType string

func (t JobSpecType) String() string {
	return string(t)
}

const (
	DirectRequestJobSpec     JobSpecType = "directrequest"
	FluxMonitorJobSpec       JobSpecType = "fluxmonitor"
	OffChainReportingJobSpec JobSpecType = "offchainreporting"
	KeeperJobSpec            JobSpecType = "keeper"
	CronJobSpec              JobSpecType = "cron"
	VRFJobSpec               JobSpecType = "vrf"
	WebhookJobSpec           JobSpecType = "webhook"
)

// DirectRequestSpec defines the spec details of a DirectRequest Job
type DirectRequestSpec struct {
	ContractAddress          ethkey.EIP55Address      `json:"contractAddress"`
	MinIncomingConfirmations clnull.Uint32            `json:"minIncomingConfirmations"`
	MinContractPayment       *assets.Link             `json:"minContractPaymentLinkJuels"`
	Requesters               models.AddressCollection `json:"requesters"`
	Initiator                string                   `json:"initiator"`
	CreatedAt                time.Time                `json:"createdAt"`
	UpdatedAt                time.Time                `json:"updatedAt"`
}

// NewDirectRequestSpec initializes a new DirectRequestSpec from a
// job.DirectRequestSpec
func NewDirectRequestSpec(spec *job.DirectRequestSpec) *DirectRequestSpec {
	return &DirectRequestSpec{
		ContractAddress:          spec.ContractAddress,
		MinIncomingConfirmations: spec.MinIncomingConfirmations,
		MinContractPayment:       spec.MinContractPayment,
		Requesters:               spec.Requesters,
		// This is hardcoded to runlog. When we support other intiators, we need
		// to change this
		Initiator: "runlog",
		CreatedAt: spec.CreatedAt,
		UpdatedAt: spec.UpdatedAt,
	}
}

// FluxMonitorSpec defines the spec details of a FluxMonitor Job
type FluxMonitorSpec struct {
	ContractAddress     ethkey.EIP55Address `json:"contractAddress"`
	Threshold           float32             `json:"threshold"`
	AbsoluteThreshold   float32             `json:"absoluteThreshold"`
	PollTimerPeriod     string              `json:"pollTimerPeriod"`
	PollTimerDisabled   bool                `json:"pollTimerDisabled"`
	IdleTimerPeriod     string              `json:"idleTimerPeriod"`
	IdleTimerDisabled   bool                `json:"idleTimerDisabled"`
	DrumbeatEnabled     bool                `json:"drumbeatEnabled"`
	DrumbeatSchedule    *string             `json:"drumbeatSchedule"`
	DrumbeatRandomDelay *string             `json:"drumbeatRandomDelay"`
	MinPayment          *assets.Link        `json:"minPayment"`
	CreatedAt           time.Time           `json:"createdAt"`
	UpdatedAt           time.Time           `json:"updatedAt"`
}

// NewFluxMonitorSpec initializes a new DirectFluxMonitorSpec from a
// job.FluxMonitorSpec
func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec {
	var drumbeatSchedulePtr *string
	if spec.DrumbeatEnabled {
		drumbeatSchedulePtr = &spec.DrumbeatSchedule
	}
	var drumbeatRandomDelayPtr *string
	if spec.DrumbeatRandomDelay > 0 {
		drumbeatRandomDelay := spec.DrumbeatRandomDelay.String()
		drumbeatRandomDelayPtr = &drumbeatRandomDelay
	}
	return &FluxMonitorSpec{
		ContractAddress:     spec.ContractAddress,
		Threshold:           spec.Threshold,
		AbsoluteThreshold:   spec.AbsoluteThreshold,
		PollTimerPeriod:     spec.PollTimerPeriod.String(),
		PollTimerDisabled:   spec.PollTimerDisabled,
		IdleTimerPeriod:     spec.IdleTimerPeriod.String(),
		IdleTimerDisabled:   spec.IdleTimerDisabled,
		DrumbeatEnabled:     spec.DrumbeatEnabled,
		DrumbeatSchedule:    drumbeatSchedulePtr,
		DrumbeatRandomDelay: drumbeatRandomDelayPtr,
		MinPayment:          spec.MinPayment,
		CreatedAt:           spec.CreatedAt,
		UpdatedAt:           spec.UpdatedAt,
	}
}

// OffChainReportingSpec defines the spec details of a OffChainReporting Job
type OffChainReportingSpec struct {
	ContractAddress                        ethkey.EIP55Address  `json:"contractAddress"`
	P2PPeerID                              *p2pkey.PeerID       `json:"p2pPeerID"`
	P2PBootstrapPeers                      pq.StringArray       `json:"p2pBootstrapPeers"`
	IsBootstrapPeer                        bool                 `json:"isBootstrapPeer"`
	EncryptedOCRKeyBundleID                *models.Sha256Hash   `json:"keyBundleID"`
	TransmitterAddress                     *ethkey.EIP55Address `json:"transmitterAddress"`
	ObservationTimeout                     models.Interval      `json:"observationTimeout"`
	BlockchainTimeout                      models.Interval      `json:"blockchainTimeout"`
	ContractConfigTrackerSubscribeInterval models.Interval      `json:"contractConfigTrackerSubscribeInterval"`
	ContractConfigTrackerPollInterval      models.Interval      `json:"contractConfigTrackerPollInterval"`
	ContractConfigConfirmations            uint16               `json:"contractConfigConfirmations"`
	CreatedAt                              time.Time            `json:"createdAt"`
	UpdatedAt                              time.Time            `json:"updatedAt"`
}

// NewOffChainReportingSpec initializes a new OffChainReportingSpec from a
// job.OffchainReportingOracleSpec
func NewOffChainReportingSpec(spec *job.OffchainReportingOracleSpec) *OffChainReportingSpec {
	return &OffChainReportingSpec{
		ContractAddress:                        spec.ContractAddress,
		P2PPeerID:                              spec.P2PPeerID,
		P2PBootstrapPeers:                      spec.P2PBootstrapPeers,
		IsBootstrapPeer:                        spec.IsBootstrapPeer,
		EncryptedOCRKeyBundleID:                spec.EncryptedOCRKeyBundleID,
		TransmitterAddress:                     spec.TransmitterAddress,
		ObservationTimeout:                     spec.ObservationTimeout,
		BlockchainTimeout:                      spec.BlockchainTimeout,
		ContractConfigTrackerSubscribeInterval: spec.ContractConfigTrackerSubscribeInterval,
		ContractConfigTrackerPollInterval:      spec.ContractConfigTrackerPollInterval,
		ContractConfigConfirmations:            spec.ContractConfigConfirmations,
		CreatedAt:                              spec.CreatedAt,
		UpdatedAt:                              spec.UpdatedAt,
	}
}

// PipelineSpec defines the spec details of the pipeline
type PipelineSpec struct {
	ID           int32  `json:"id"`
	DotDAGSource string `json:"dotDagSource"`
}

// NewPipelineSpec generates a new PipelineSpec from a pipeline.Spec
func NewPipelineSpec(spec *pipeline.Spec) PipelineSpec {
	return PipelineSpec{
		ID:           spec.ID,
		DotDAGSource: spec.DotDagSource,
	}
}

// KeeperSpec defines the spec details of a Keeper Job
type KeeperSpec struct {
	ContractAddress ethkey.EIP55Address `json:"contractAddress"`
	FromAddress     ethkey.EIP55Address `json:"fromAddress"`
	CreatedAt       time.Time           `json:"createdAt"`
	UpdatedAt       time.Time           `json:"updatedAt"`
}

// NewKeeperSpec generates a new KeeperSpec from a job.KeeperSpec
func NewKeeperSpec(spec *job.KeeperSpec) *KeeperSpec {
	return &KeeperSpec{
		ContractAddress: spec.ContractAddress,
		FromAddress:     spec.FromAddress,
		CreatedAt:       spec.CreatedAt,
		UpdatedAt:       spec.UpdatedAt,
	}
}

// WebhookSpec defines the spec details of a Webhook Job
type WebhookSpec struct {
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

// NewWebhookSpec generates a new WebhookSpec from a job.WebhookSpec
func NewWebhookSpec(spec *job.WebhookSpec) *WebhookSpec {
	return &WebhookSpec{
		CreatedAt: spec.CreatedAt,
		UpdatedAt: spec.UpdatedAt,
	}
}

// CronSpec defines the spec details of a Cron Job
type CronSpec struct {
	CronSchedule string    `json:"schedule" tom:"schedule"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

// NewCronSpec generates a new CronSpec from a job.CronSpec
func NewCronSpec(spec *job.CronSpec) *CronSpec {
	return &CronSpec{
		CronSchedule: spec.CronSchedule,
		CreatedAt:    spec.CreatedAt,
		UpdatedAt:    spec.UpdatedAt,
	}
}

type VRFSpec struct {
	CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"`
	PublicKey          secp256k1.PublicKey `json:"publicKey"`
	Confirmations      uint32              `json:"confirmations"`
	CreatedAt          time.Time           `json:"createdAt"`
	UpdatedAt          time.Time           `json:"updatedAt"`
}

func NewVRFSpec(spec *job.VRFSpec) *VRFSpec {
	return &VRFSpec{
		CoordinatorAddress: spec.CoordinatorAddress,
		PublicKey:          spec.PublicKey,
		Confirmations:      spec.Confirmations,
		CreatedAt:          spec.CreatedAt,
		UpdatedAt:          spec.UpdatedAt,
	}
}

// JobError represents errors on the job
type JobError struct {
	ID          int64     `json:"id"`
	Description string    `json:"description"`
	Occurrences uint      `json:"occurrences"`
	CreatedAt   time.Time `json:"createdAt"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

func NewJobError(e job.SpecError) JobError {
	return JobError{
		ID:          e.ID,
		Description: e.Description,
		Occurrences: e.Occurrences,
		CreatedAt:   e.CreatedAt,
		UpdatedAt:   e.UpdatedAt,
	}
}

// JobResource represents a JobResource
type JobResource struct {
	JAID
	Name                  string                 `json:"name"`
	Type                  JobSpecType            `json:"type"`
	SchemaVersion         uint32                 `json:"schemaVersion"`
	MaxTaskDuration       models.Interval        `json:"maxTaskDuration"`
	ExternalJobID         uuid.UUID              `json:"externalJobID"`
	DirectRequestSpec     *DirectRequestSpec     `json:"directRequestSpec"`
	FluxMonitorSpec       *FluxMonitorSpec       `json:"fluxMonitorSpec"`
	CronSpec              *CronSpec              `json:"cronSpec"`
	OffChainReportingSpec *OffChainReportingSpec `json:"offChainReportingOracleSpec"`
	KeeperSpec            *KeeperSpec            `json:"keeperSpec"`
	VRFSpec               *VRFSpec               `json:"vrfSpec"`
	WebhookSpec           *WebhookSpec           `json:"webhookSpec"`
	PipelineSpec          PipelineSpec           `json:"pipelineSpec"`
	Errors                []JobError             `json:"errors"`
}

// NewJobResource initializes a new JSONAPI job resource
func NewJobResource(j job.Job) *JobResource {
	resource := &JobResource{
		JAID:            NewJAIDInt32(j.ID),
		Name:            j.Name.ValueOrZero(),
		Type:            JobSpecType(j.Type),
		SchemaVersion:   j.SchemaVersion,
		MaxTaskDuration: j.MaxTaskDuration,
		PipelineSpec:    NewPipelineSpec(j.PipelineSpec),
		ExternalJobID:   j.ExternalJobID,
	}

	switch j.Type {
	case job.DirectRequest:
		resource.DirectRequestSpec = NewDirectRequestSpec(j.DirectRequestSpec)
	case job.FluxMonitor:
		resource.FluxMonitorSpec = NewFluxMonitorSpec(j.FluxMonitorSpec)
	case job.Cron:
		resource.CronSpec = NewCronSpec(j.CronSpec)
	case job.OffchainReporting:
		resource.OffChainReportingSpec = NewOffChainReportingSpec(j.OffchainreportingOracleSpec)
	case job.Keeper:
		resource.KeeperSpec = NewKeeperSpec(j.KeeperSpec)
	case job.VRF:
		resource.VRFSpec = NewVRFSpec(j.VRFSpec)
	case job.Webhook:
		resource.WebhookSpec = NewWebhookSpec(j.WebhookSpec)
	}

	jes := []JobError{}
	for _, e := range j.JobSpecErrors {
		jes = append(jes, NewJobError((e)))
	}
	resource.Errors = jes

	return resource
}

// NewJobResources initializes a slice of JSONAPI job resources
func NewJobResources(js []job.Job) []JobResource {
	rs := []JobResource{}

	for _, j := range js {
		rs = append(rs, *NewJobResource(j))
	}

	return rs
}

// GetName implements the api2go EntityNamer interface
func (r JobResource) GetName() string {
	return "jobs"
}
