import Joi from 'joi'
import { BaseJsonService } from '../index.js'

const schema = Joi.object({
  status: Joi.allow(
    'insecure',
    'outofdate',
    'notsouptodate',
    'uptodate',
    'none'
  ).required(),
}).required()

const queryParamSchema = Joi.object({
  path: Joi.string(),
}).required()

const statusMap = {
  insecure: {
    color: 'red',
    message: 'insecure',
  },
  outofdate: {
    color: 'red',
    message: 'out of date',
  },
  notsouptodate: {
    color: 'yellow',
    message: 'up to date',
  },
  uptodate: {
    color: 'brightgreen',
    message: 'up to date',
  },
  none: {
    color: 'brightgreen',
    message: 'none',
  },
}

export default class David extends BaseJsonService {
  static category = 'dependencies'
  static route = {
    base: 'david',
    pattern: ':kind(dev|optional|peer)?/:user/:repo',
    queryParamSchema,
  }

  static examples = [
    {
      title: 'David',
      namedParams: { user: 'expressjs', repo: 'express' },
      staticPreview: this.render({ status: 'uptodate' }),
    },
    {
      title: 'David (path)',
      namedParams: { user: 'babel', repo: 'babel' },
      queryParams: { path: 'packages/babel-core' },
      staticPreview: this.render({ status: 'uptodate' }),
    },
  ]

  static defaultBadgeData = { label: 'dependencies' }

  static render({ status, kind }) {
    return {
      message: statusMap[status].message,
      color: statusMap[status].color,
      label: `${kind ? `${kind} ` : ''}dependencies`,
    }
  }

  async fetch({ kind, user, repo, path }) {
    const url = `https://david-dm.org/${user}/${repo}/${
      kind ? `${kind}-` : ''
    }info.json`

    return this._requestJson({
      schema,
      url,
      options: { qs: { path } },
      errorMessages: {
        /* note:
        david returns a 504 response for 'not found'
        e.g: https://david-dm.org/foo/barbaz/info.json
        not a 404 so we can't handle 'not found' cleanly
        because this might also be some other error.
        */
        504: 'repo or path not found or david internal error',
      },
    })
  }

  async handle({ kind, user, repo }, { path }) {
    const json = await this.fetch({ kind, user, repo, path })
    return this.constructor.render({ status: json.status, kind })
  }
}

@@ -1547,105 +1547,315 @@
     
-const url = %60https://david-dm.org/$%7Buser%7D/$%7Brepo%7D/$%7B%0A      kind ? %60$%7Bkind%7D-%60 : ''%0A    %7Dinfo.json%60
+// Note: David does not return canonical 404 response codes for 'not found'%0A    // cases, but will instead return various 50x errors. Accordingly we account%0A    // for both 'not found' as well as typical/real internal server errors.%0A    const notFoundError = 'repo or path not found or david internal error'
 %0A%0A  
@@ -1906,16 +1906,66 @@
      url
+: %60https://status.david-dm.org/gh/$%7Buser%7D/$%7Brepo%7D%60
 ,%0A      
@@ -1985,16 +1985,28 @@
 : %7B path
+, type: kind
  %7D %7D,%0A  
@@ -2038,307 +2038,82 @@
     
-/* note:%0A        david returns a 504 response for 'not f
+502: notF
 ound
-'%0A        e.g: https://david-dm.org/foo/barbaz/info.json%0A        not a 404 so we can't handle 'not f
+Error,%0A        503: notF
 ound
-' cleanly%0A        because this might also be some other error.%0A        */%0A        504: 'repo or path
+Error,%0A        504:
  not
- f
+F
 ound
- or david internal e
+E
 rror
-'
 ,%0A  

switch to David status API and update error handling (#7070)