// @flow

import axios from 'axios'
import moment from 'moment'
import type { ID } from '../../common/model/flowtypes.js'

import NotificationService from './NotificationService'

type JobStatus = 'RUNNING' | 'SUBMITTED' | 'DONE' | 'ERROR' | 'FAILED' 

export class Job {
  id: ID
  stepId: ID
  userName: string
  state: JobStatus 
  message: string
  createTime: moment
  updateTime: moment

  token: string

  // eslint-disable-next-line
  pollingJob: ?IntervalID = null

  notificationService: NotificationService

  constructor(id: ID, stepId: ID, userName: string, state: JobStatus, message: string, token: string) {
    this.id = id
    this.stepId = stepId 
    this.userName = userName
    this.state = state
    this.message = message
    this.createTime = moment()
    this.updateTime = this.createTime

    this.token = token
  }

  setNotificationService(notificationService: NotificationService) {
    this.notificationService = notificationService
  }

  setStatus(state: JobStatus, message: string) {
    this.state = state
    this.message = message
    this.updateTime = moment()
  }

  startStatusPolling(apiURL: string, interval: number = 10000) {
    this.endStatusPolling() 

    this.pollingJob = setInterval(() => {
      if (this.state === 'DONE' || this.state === 'ERROR') {
        this.endStatusPolling()
      }

      axios({
        method: 'GET',
        url: `${apiURL}/jobs/${this.id}/poll`,
        headers: {
          'content-type': 'application/json',
          'authorization': this.token,
        }
      })
      .then(res=>{
        if (res.data.code !== 200) {
          this.endStatusPolling()
          throw new Error(res.data.message)
        }

        if (typeof res.data.data === 'object' && res.data.data.message) {
          this.endStatusPolling()
          throw new Error(res.data.data.message)
        }
        
        this.setStatus(res.data.data.state, res.data.data.message)
          
        if (this.state === 'DONE' || this.state === 'ERROR' || this.state === 'FAILED') {
          this.notificationService.notify(`Job ${this.state}`, {
            body: `Job ${this.id} changes state to ${this.state}`
          })
          this.endStatusPolling()
        }
      })
      .catch(err => {
      })
    }, interval)
  }

  endStatusPolling() {
    if (this.pollingJob !== null) {
      clearInterval(this.pollingJob)
      this.pollingJob = null
      console.log('end job state polling for', this.pollingJob)
    }
  }
}

export default class JobService {
  apiURL: string
  notificationService: NotificationService

  jobs: Array<Job> = []

  constructor(apiURL :string, notificationService: NotificationService) {
    this.apiURL = apiURL
    this.notificationService = notificationService
  }

  getServiceName() {
    return 'JobService'
  }

  getJobs() {
    return this.jobs
  }

  newJob(id: ID, stepId: ID, userName: string, token: string) {
    if (this.jobs.find(job => job.id === id)) {
      return
    }
    let job = new Job(id, stepId, userName, 'SUBMITTED', '', token)
    this.jobs.push(job)
    job.setNotificationService(this.notificationService)
    job.startStatusPolling(this.apiURL, 3000)
  }

  getJobsByStepId(stepId: ID, orderBy?: 'createTime' | 'updateTime') : Promise<Array<any>> {
    /*
    let filtered = this.jobs.filter(job => job.stepId === stepId)
    switch(orderBy) {
      case 'createTime':
        return filtered.sort((a, b) => a.createTime.diff(b.createTime))
      case 'updateTime':
        return filtered.sort((a, b) => a.updateTime.diff(b.updateTime))
      default: 
        return filtered
    }
    */
    return axios({
      method: 'GET',
      url: `${this.apiURL}/goal/${stepId}/jobs?skip=0&size=10`,
      headers: {
        'content-type': 'application/json',
        'authorization': '', // TODO: add token here
      }
    })
    .then(res=>{
      if (res.data.code !== 200) {
        throw new Error(res.data.message)
      }
      console.log('get job by stepId', res.data.data)
      return res.data.data
    })
    .catch(err => {
      return []
    })
    
  }

  getJobsByStatus(state: JobStatus, orderBy?: 'createTime' | 'updateTime'): Array<Job> {
    let filtered = this.jobs.filter(job => job.state === state)
    switch(orderBy) {
      case 'createTime':
        return filtered.sort((a, b) => a.createTime.diff(b.createTime))
      case 'updateTime':
        return filtered.sort((a, b) => a.updateTime.diff(b.updateTime))
      default: 
        return filtered
    }
  }
}
