type Portal {
  id: ID!
  user: User!
  datacenter: Datacenter!
  deploymentGroups(name: String, slug: String): [DeploymentGroup]
}

type User {
  id: ID!
  firstName: String!
  lastName: String!
  email: String!
  login: String!
}

enum DeploymentGroupStatus {
  ACTIVE
  PROVISIONING
  DELETING
  DELETED
  UNKNOWN
}

type DeploymentGroup {
  id: ID!
  name: String!
  slug: String!
  services(name: String, slug: String): [Service]
  version: Version
  history: [Version]
  imported: Boolean
  status: DeploymentGroupStatus
}

type ServiceScale {
  id: ID!
  serviceName: String!
  replicas: Int!
}

enum ConvergenceActionType {
  NOOP
  CREATE
  RECREATE
  REMOVE
  START
  EXISTING # special status to mark existing ids in previous version
}

type ConvergenceAction {
  id: ID!
  type: ConvergenceActionType!
  service: String! # service name
  toProcess: Int # merely used for book keeping
  processed: [String] # merely used for book keeping
  machines: [String]! # current instance machine ids
}

type Version {
  id: ID!
  manifest: Manifest
  scale(serviceName: String): [ServiceScale]
  plan: [ConvergenceAction]
  hasPlan: Boolean
  error: String
}

enum ManifestType {
  COMPOSE
  MARIPOSA
}

enum ManifestFormat {
  JSON
  YAML
}

type KeyValue {
  id: ID!
  name: String!
  value: String!
}

input KeyValueInput {
  id: ID
  name: String!
  value: String!
}

type Manifest {
  id: ID!
  type: ManifestType!
  format: ManifestFormat!
  environment: String!
  files: [KeyValue]
  raw: String!
}

enum ServiceStatus {
  ACTIVE # this doesn't mean that the instances are all running
  PROVISIONING
  SCALING
  STOPPING
  STOPPED
  DELETING
  DELETED
  RESTARTING
  UNKNOWN
}

type ServiceConfig {
  id: ID!
  package: Package # we don't have this in current mock data
  environment: [KeyValue]
  image: String # used only for config
  labels: [KeyValue]
  ports: [String]
}

# immutable
type Service {
  id: ID! # unique id for db row
  hash: String # unique id for version of service
  name: String! # human readable name
  slug: String!
  instances(name: String, machineId: ID, status: InstanceStatus): [Instance]!
  connections: [String] # list of serviceIds
  branches(name: String, slug: String): [Service]
  config: ServiceConfig
  status: ServiceStatus
}

# for metrics max / min (I guess)
type Package {
  id: ID!
  name: String!
  type: String!
  memory: Float!
  disk: Float!
  swap: Float!
  lwps: Int!
  vcpus: Int!
  version: String!
  group: String!
}

enum InstanceStatus {
  PROVISIONING
  READY
  ACTIVE # vm only: When used in ListVms, denotes machines that are not 'destroyed' or 'failed'
  RUNNING
  STOPPING
  STOPPED
  OFFLINE
  DELETED
  DESTROYED # vm only
  FAILED
  INCOMPLETE # vm only
  UNKNOWN
}

enum HealthyStatus {
  HEALTHY
  UNHEALTHY
  MAINTENANCE
  UNKNOWN
  UNAVAILABLE
}

type Metric {
  time: String!
  value: Float!
}

enum MetricName {
  AVG_MEM_BYTES
  AVG_LOAD_PERCENT
  AGG_NETWORK_BYTES
}

type InstanceMetric {
  instance: String!
  name: MetricName!
  start: String!
  end: String!
  metrics: [Metric]
}

type Instance {
  id: ID!
  name: String!
  machineId: ID!
  primaryIp: String
  status: InstanceStatus
  healthy: HealthyStatus
  watches: [String]
  jobs: [String]
  metrics(names: [MetricName]!, start: String!, end: String!): [InstanceMetric]!
}

type Datacenter {
  id: ID!
  name: String!
  region: String!
}

# we probably wont use some of these queries or arguments
# but this way we expose the entire db through gql
type Query {
  portal: Portal
  user: User
  deploymentGroups(name: String, slug: String): [DeploymentGroup]
  deploymentGroup(id: ID, name: String, slug: String): DeploymentGroup
  serviceScales(serviceName: String, versionId: ID): [ServiceScale]
  serviceScale(id: ID!): ServiceScale
  convergenceActions(
    type: ConvergenceActionType
    service: String
    versionId: ID
  ): [ConvergenceAction]
  convergenceAction(id: ID!): ConvergenceAction
  versions(manifestId: ID, deploymentGroupId: ID): [Version]
  version(id: ID, manifestId: ID): Version
  manifests(type: String, deploymentGroupId: ID): [Manifest]
  manifest(id: ID!): Manifest
  services(
    name: String
    slug: String
    parentId: ID
    deploymentGroupId: ID
    deploymentGroupSlug: String
  ): [Service]
  service(id: ID, hash: ID): Service
  packages(
    name: String
    type: String
    memory: Int
    disk: Int
    swap: Int
    lwps: Int
    vcpus: Int
    version: String
    group: String
  ): [Package]
  package(id: ID!): Package
  instances(
    name: String
    machineId: ID
    status: InstanceStatus
    serviceId: ID
    serviceSlug: String
    deploymentGroupId: ID
    deploymentGroupSlug: String
  ): [Instance]
  instance(id: ID!): Instance
  datacenter(id: ID, region: String): Datacenter
  datacenters: [Datacenter]
  config(
    deploymentGroupName: String!
    type: ManifestType!
    format: ManifestFormat!
    environment: String!
    files: [KeyValueInput]!
    raw: String!
  ): [Service]
  importableDeploymentGroups: [DeploymentGroup]
  # start and end should be .toISOString() date strings
  metrics(
    deploymentGroupId: ID!
    names: [MetricName]!
    instances: [ID]!
    start: String!
    end: String!
  ): [InstanceMetric]
}

type Mutation {
  createDeploymentGroup(name: String!): DeploymentGroup
  updateDeploymentGroup(id: ID!, name: String!): DeploymentGroup
  deleteDeploymentGroup(id: ID!): DeploymentGroup
  provisionManifest(
    deploymentGroupId: ID!
    type: ManifestType!
    format: ManifestFormat!
    environment: String!
    files: [KeyValueInput]!
    raw: String!
  ): Version
  scale(serviceId: ID!, replicas: Int!): Version
  stopServices(ids: [ID]!): [Service]
  startServices(ids: [ID]!): [Service]
  restartServices(ids: [ID]!): [Service]
  deleteServices(ids: [ID]!): [Service]
  stopInstances(ids: [ID]!): [Instance]
  startInstances(ids: [ID]!): [Instance]
  restartInstances(ids: [ID]!): [Instance]
  importDeploymentGroup(deploymentGroupSlug: String!): DeploymentGroup
  deleteDeploymentGroup(id: ID!): DeploymentGroup
}
