async         = require 'async'
debug         = require('debug') 'loopback:satellizer:twitter'
qs            = require 'querystring'
request       = require 'request'
randomstring  = require 'randomstring'

common = require '../common'

module.exports = (server, options) ->

  Common      = common server, options
  Model       = server.models[options.model]

  credentials = options.credentials
  callbackUrl = options.callbackUrl

  handleFirstRequest = (callback) ->
    request.post
      url: 'https://api.twitter.com/oauth/request_token'
      oauth:
        consumer_key: credentials.public
        consumer_secret: credentials.private
    , (err, res, body) ->
      return callback err if err
      callback null, qs.parse body

  fetchAccessToken = (oauthToken, oauthVerifier, callback) ->
    request.post
      url: 'https://api.twitter.com/oauth/access_token'
      oauth:
        consumer_key: credentials.public
        consumer_secret: credentials.private
        token: oauthToken
        verifier: oauthVerifier
    , (err, res, accessToken) ->
      if err
        debug JSON.stringify err
        return callback err
      if res.statusCode isnt 200
        err = new Error accessToken
        err.status = 500
        debug JSON.stringify err
        return callback err
      callback null, qs.parse accessToken

  fetchProfile = (accessToken, callback) ->
    debug 'fetchProfile'
    request.get
      url: 'https://api.twitter.com/1.1/users/show.json?screen_name=' + accessToken.screen_name
      oauth:
        consumer_key: credentials.public
        consumer_secret: credentials.private
        oauth_token: accessToken.oauth_token
      json: true
    , (err, res, profile) ->
      if err
        debug JSON.stringify err
        return callback err
      if res.statusCode isnt 200
        err = new Error JSON.stringify profile
        err.status = 500
        debug JSON.stringify err
        return callback err
      callback null, profile

  link = (req, profile, callback) ->
    debug 'link'
    Common.current req, (err, found) ->
      if err
        debug err
        return callback err
      if found is null
        err = new Error 'not_an_account'
        err.status = 409
        debug err
        return callback err
      if found
        return link.existing profile, found, callback
      #
      query =
        where: {}
      query.where[options.mapping.id] = profile.id
      #
      Model.findOne query, (err, found) ->
        if err
          debug err
          return callback err
        return link.create profile, callback if not found
        return link.existing profile, found, callback

  link.create = (profile, callback) ->
    debug 'link.create', profile.id
    tmp =
      email: "#{profile.id}@twitter.com"
      password: randomstring.generate()
    Common.map options.mapping, profile, tmp
    Model.create tmp, (err, created) ->
      debug err if err
      return callback err, created

  link.existing = (profile, account, callback) ->
    debug 'link.existing'
    if account[options.mapping.id] and account[options.mapping.id] != profile.id
      err = new Error 'account_conflict'
      err.status = 409
      debug err
      return callback err
    Common.map options.mapping, profile, account
    account.save (err) ->
      debug err if err
      return callback err, account

  Model.twitter = (req, oauthToken, oauthVerifier, callback) ->
    debug "#{oauthToken}, #{oauthVerifier}"
    # Initial request for satellizer
    return handleFirstRequest callback if not oauthToken or not oauthVerifier
    async.waterfall [
      (done) ->
        fetchAccessToken oauthToken, oauthVerifier, done
      (accessToken, done) ->
        fetchProfile accessToken, done
      (profile, done) ->
        link req, profile, done
      (account, done) ->
        Common.authenticate account, done
    ], callback

  Model['twitter-get'] = Model.twitter

  Model.remoteMethod 'twitter-get',
    accepts: [
      {
        arg: 'req'
        type: 'object'
        http:
          source: 'req'
      }
      {
        arg: 'oauth_token'
        type: 'string'
        http:
          source: 'query'
      }
      {
        arg: 'oauth_verifier'
        type: 'string'
        http:
          source: 'query'
      }
    ]
    returns:
      arg: 'result'
      type: 'object'
      root: true
    http:
      verb: 'get'
      path: options.uri


  Model.remoteMethod 'twitter',
    accepts: [
      {
        arg: 'req'
        type: 'object'
        http:
          source: 'req'
      }
      {
        arg: 'oauth_token'
        type: 'string'
        http:
          source: 'form'
      }
      {
        arg: 'oauth_verifier'
        type: 'string'
        http:
          source: 'form'
      }
    ]
    returns:
      arg: 'result'
      type: 'object'
      root: true
    http:
      verb: 'post'
      path: options.uri

  return
