UserCodeProblem = require './UserCodeProblem'
Handler = require '../commons/Handler'

class UserCodeProblemHandler extends Handler
  modelClass: UserCodeProblem
  jsonSchema: require '../../app/schemas/models/user_code_problem'
  editableProperties: [
    'code'
    'codeSnippet'
    'errHint'
    'errId'
    'errLevel'
    'errMessage'
    'errMessageNoLineInfo'
    'errRange'
    'errType'
    'language'
    'levelID'
  ]

  makeNewInstance: (req) ->
    ucp = super(req)
    ucp.set('creator', req.user._id)
    ucp

  getByRelationship: (req, res, args...) ->
    return @getCommonLevelProblemsBySlug(req, res) if args[1] is 'common_problems'
    super(arguments...)

  getCommonLevelProblemsBySlug: (req, res) ->
    # Returns an ordered array of common user code problems with: language, message, hint, count
    # Parameters:
    # slug - level slug
    # startDay - Inclusive, optional, e.g. '2014-12-14'
    # endDay - Exclusive, optional, e.g. '2014-12-16'

    levelSlug = req.query.slug or req.body.slug
    startDay = req.query.startDay or req.body.startDay
    endDay = req.query.endDay or req.body.endDay

    return @sendSuccess res, [] unless levelSlug?

    # Cache results for 1 day
    @commonLevelProblemsCache ?= {}
    @commonLevelProblemsCachedSince ?= new Date()
    if (new Date()) - @commonLevelProblemsCachedSince > 86400 * 1000  # Dumb cache expiration
      @commonLevelProblemsCache = {}
      @commonLevelProblemsCachedSince = new Date()
    cacheKey = levelSlug
    cacheKey += 's' + startDay if startDay?
    cacheKey += 'e' + endDay if endDay?
    return @sendSuccess res, commonProblems if commonProblems = @commonLevelProblemsCache[cacheKey]

    # Build query
    match = if startDay? or endDay? then {$match: {$and: []}} else {$match: {}}
    match["$match"]["$and"].push created: {$gte: new Date(startDay + "T00:00:00.000Z")} if startDay?
    match["$match"]["$and"].push created: {$lt: new Date(endDay + "T00:00:00.000Z")} if endDay?
    group = {"$group": {"_id": {"errMessage": "$errMessageNoLineInfo", "errHint": "$errHint", "language": "$language", "levelID": "$levelID"}, "count": {"$sum": 1}}}
    sort = { $sort : { "_id.levelID": 1, count : -1, "_id.language": 1 } }
    query = UserCodeProblem.aggregate match, group, sort

    query.exec (err, data) =>
      if err? then return @sendDatabaseError res, err

      # Build per-level common problem lists
      commonProblems = {}
      for item in data
        levelID = item._id.levelID
        commonProblems[levelID] ?= []
        commonProblems[levelID].push
          language: item._id.language
          message: item._id.errMessage
          hint: item._id.errHint
          count: item.count

      # Cache all the levels
      for levelID of commonProblems
        cacheKey = levelID
        cacheKey += 's' + startDay if startDay?
        cacheKey += 'e' + endDay if endDay?
        @commonLevelProblemsCache[cacheKey] = commonProblems[levelID]
      @sendSuccess res, commonProblems[levelSlug]

module.exports = new UserCodeProblemHandler()