syntax = "v1"

type (
	JobTemplatePath {
		Type string `path:"type" validate:"required"` // template type
	}

	JobIDPath {
		ID string `path:"id" validate:"required"` // job run id
	}

	JobScheduleIDPath {
		ID string `path:"id" validate:"required"` // schedule id
	}

	ListJobsReq {
		Scope    string `form:"scope,optional"` // filter by scope
		ScopeID  string `form:"scope_id,optional"` // filter by scope id
		Page     int64  `form:"page,optional"` // page number starting at 1
		PageSize int64  `form:"pageSize,optional"` // page size
	}

	ListJobSchedulesReq {
		Scope    string `form:"scope,optional"` // filter by scope
		ScopeID  string `form:"scope_id,optional"` // filter by scope id
		Page     int64  `form:"page,optional"` // page number starting at 1
		PageSize int64  `form:"pageSize,optional"` // page size
	}

	ListJobEventsReq {
		ID    string `path:"id" validate:"required"` // job run id
		Limit int64  `form:"limit,optional"` // max events
	}

	CancelJobReq {
		ID     string `path:"id" validate:"required"` // job run id
		Reason string `json:"reason,optional"` // cancel reason
	}

	CreateJobReq {
		TemplateType string                 `json:"template_type" validate:"required"` // job template type
		Scope        string                 `json:"scope" validate:"required,oneof=user account system persona brand"` // job scope
		ScopeID      string                 `json:"scope_id" validate:"required"` // scope id
		Payload      map[string]interface{} `json:"payload,optional"` // job payload
	}

	UpsertJobTemplateReq {
		Type              string                   `path:"type" validate:"required"` // template type
		Version           int                      `json:"version,optional"` // template version
		Name              string                   `json:"name" validate:"required"` // display name
		Description       string                   `json:"description,optional"` // description
		Enabled           bool                     `json:"enabled"` // enabled flag
		Repeatable        bool                     `json:"repeatable"` // repeatable flag
		ConcurrencyPolicy string                   `json:"concurrency_policy,optional"` // concurrency policy
		DedupeKeys        []string                 `json:"dedupe_keys,optional"` // dedupe keys
		TimeoutSeconds    int                      `json:"timeout_seconds,optional"` // timeout seconds
		CancelPolicy      JobCancelPolicyData      `json:"cancel_policy,optional"` // cancel policy
		RetryPolicy       JobRetryPolicyData       `json:"retry_policy,optional"` // retry policy
		Steps             []JobTemplateStepData    `json:"steps" validate:"required,min=1,dive"` // steps
	}

	CreateJobScheduleReq {
		TemplateType    string                 `json:"template_type" validate:"required"` // template type
		Scope           string                 `json:"scope" validate:"required,oneof=user account system persona brand"` // scope
		ScopeID         string                 `json:"scope_id" validate:"required"` // scope id
		Cron            string                 `json:"cron" validate:"required"` // cron expression
		Timezone        string                 `json:"timezone,optional"` // timezone
		PayloadTemplate map[string]interface{} `json:"payload_template,optional"` // payload template
		Enabled         bool                   `json:"enabled"` // enabled flag
	}

	UpdateJobScheduleReq {
		ID              string                 `path:"id" validate:"required"` // schedule id
		Cron            string                 `json:"cron,optional"` // cron expression
		Timezone        string                 `json:"timezone,optional"` // timezone
		PayloadTemplate map[string]interface{} `json:"payload_template,optional"` // payload template
		Enabled         *bool                  `json:"enabled,optional"` // enabled flag
	}

	JobCancelPolicyData {
		Supported    bool   `json:"supported"`
		Mode         string `json:"mode"`
		GraceSeconds int    `json:"grace_seconds"`
	}

	JobRetryPolicyData {
		MaxAttempts    int   `json:"max_attempts"`
		BackoffSeconds []int `json:"backoff_seconds"`
	}

	JobTemplateStepData {
		ID             string `json:"id"`
		Name           string `json:"name"`
		WorkerType     string `json:"worker_type"`
		TimeoutSeconds int    `json:"timeout_seconds"`
		Cancelable     bool   `json:"cancelable"`
	}

	JobTemplateData {
		Type              string                `json:"type"`
		Version           int                   `json:"version"`
		Name              string                `json:"name"`
		Description       string                `json:"description"`
		Enabled           bool                  `json:"enabled"`
		Repeatable        bool                  `json:"repeatable"`
		ConcurrencyPolicy string                `json:"concurrency_policy"`
		DedupeKeys        []string              `json:"dedupe_keys"`
		TimeoutSeconds    int                   `json:"timeout_seconds"`
		CancelPolicy      JobCancelPolicyData   `json:"cancel_policy"`
		RetryPolicy       JobRetryPolicyData    `json:"retry_policy"`
		Steps             []JobTemplateStepData `json:"steps"`
	}

	JobTemplateListData {
		List []JobTemplateData `json:"list"`
	}

	JobStepProgressData {
		ID        string `json:"id"`
		Status    string `json:"status"`
		StartedAt *int64 `json:"started_at,optional"`
		EndedAt   *int64 `json:"ended_at,optional"`
		Message   string `json:"message,optional"`
	}

	JobProgressData {
		Summary    string                `json:"summary"`
		Percentage int                   `json:"percentage"`
		Steps      []JobStepProgressData `json:"steps"`
	}

	JobData {
		ID                string                 `json:"id"`
		TemplateType      string                 `json:"template_type"`
		TemplateVersion   int                    `json:"template_version"`
		Scope             string                 `json:"scope"`
		ScopeID           string                 `json:"scope_id"`
		Status            string                 `json:"status"`
		Phase             string                 `json:"phase"`
		WorkerType        string                 `json:"worker_type"`
		Payload           map[string]interface{} `json:"payload"`
		Progress          JobProgressData        `json:"progress"`
		Result            map[string]interface{} `json:"result,optional"`
		Error             string                 `json:"error,optional"`
		Attempt           int                    `json:"attempt"`
		MaxAttempts       int                    `json:"max_attempts"`
		CancelRequestedAt *int64                 `json:"cancel_requested_at,optional"`
		CancelReason      string                 `json:"cancel_reason,optional"`
		StartedAt         *int64                 `json:"started_at,optional"`
		CompletedAt       *int64                 `json:"completed_at,optional"`
		CreateAt          int64                  `json:"create_at"`
		UpdateAt          int64                  `json:"update_at"`
	}

	JobListData {
		Pagination PaginationData `json:"pagination"`
		List       []JobData      `json:"list"`
	}

	JobScheduleData {
		ID              string                 `json:"id"`
		TemplateType    string                 `json:"template_type"`
		Scope           string                 `json:"scope"`
		ScopeID         string                 `json:"scope_id"`
		Enabled         bool                   `json:"enabled"`
		Cron            string                 `json:"cron"`
		Timezone        string                 `json:"timezone"`
		PayloadTemplate map[string]interface{} `json:"payload_template"`
		LastRunAt       *int64                 `json:"last_run_at,optional"`
		NextRunAt       int64                  `json:"next_run_at"`
		CreateAt        int64                  `json:"create_at"`
		UpdateAt        int64                  `json:"update_at"`
	}

	JobScheduleListData {
		Pagination PaginationData  `json:"pagination"`
		List       []JobScheduleData `json:"list"`
	}

	JobEventData {
		ID       string                 `json:"id"`
		JobID    string                 `json:"job_id"`
		Type     string                 `json:"type"`
		From     string                 `json:"from,optional"`
		To       string                 `json:"to,optional"`
		Message  string                 `json:"message"`
		Metadata map[string]interface{} `json:"metadata,optional"`
		CreateAt int64                  `json:"create_at"`
	}

	JobEventListData {
		List []JobEventData `json:"list"`
	}
)

@server(
	group:      job
	prefix:     /api/v1
	middleware: AuthJWT
	tags:       "Job - Core"
	summary:    "Generic job templates, runs, schedules, cancel, and retry. Requires Bearer JWT."
)
service gateway {
	@handler listJobTemplates
	get /job/templates returns (JobTemplateListData)

	@handler getJobTemplate
	get /job/templates/:type (JobTemplatePath) returns (JobTemplateData)

	@handler upsertJobTemplate
	put /job/templates/:type (UpsertJobTemplateReq) returns (JobTemplateData)

	@handler createJob
	post /jobs (CreateJobReq) returns (JobData)

	@handler getJob
	get /jobs/:id (JobIDPath) returns (JobData)

	@handler listJobs
	get /jobs (ListJobsReq) returns (JobListData)

	@handler listJobEvents
	get /jobs/:id/events (ListJobEventsReq) returns (JobEventListData)

	@handler cancelJob
	post /jobs/:id/cancel (CancelJobReq) returns (JobData)

	@handler retryJob
	post /jobs/:id/retry (JobIDPath) returns (JobData)

	@handler listJobSchedules
	get /job/schedules (ListJobSchedulesReq) returns (JobScheduleListData)

	@handler createJobSchedule
	post /job/schedules (CreateJobScheduleReq) returns (JobScheduleData)

	@handler updateJobSchedule
	put /job/schedules/:id (UpdateJobScheduleReq) returns (JobScheduleData)

	@handler enableJobSchedule
	post /job/schedules/:id/enable (JobScheduleIDPath) returns (JobScheduleData)

	@handler disableJobSchedule
	post /job/schedules/:id/disable (JobScheduleIDPath) returns (JobScheduleData)

	@handler deleteJobSchedule
	delete /job/schedules/:id (JobScheduleIDPath)
}