request = require 'request'
FileWriter = require('../../infrastructure/FileWriter')
_ = require "underscore"
urlValidator = require 'valid-url'
Settings = require 'settings-sharelatex'

UrlFetchFailedError = (message) ->
	error = new Error(message)
	error.name = 'UrlFetchFailedError'
	error.__proto__ = UrlFetchFailedError.prototype
	return error
UrlFetchFailedError.prototype.__proto__ = Error.prototype

InvalidUrlError = (message) ->
	error = new Error(message)
	error.name = 'InvalidUrlError'
	error.__proto__ = InvalidUrlError.prototype
	return error
InvalidUrlError.prototype.__proto__ = Error.prototype

module.exports = UrlAgent = {
	UrlFetchFailedError: UrlFetchFailedError
	InvalidUrlError: InvalidUrlError

	sanitizeData: (data) ->
		return {
			url: @._prependHttpIfNeeded(data.url)
		}

	canCreate: (data) -> true

	decorateLinkedFileData: (data, callback = (err, newData) ->) ->
		return callback(null, data)

	checkAuth: (project_id, data, current_user_id, callback = (error, allowed)->) ->
		callback(null, true)

	writeIncomingFileToDisk: (project_id, data, current_user_id, callback = (error, fsPath) ->) ->
		callback = _.once(callback)
		url = data.url
		if !urlValidator.isWebUri(url)
			return callback(new InvalidUrlError("invalid url: #{url}"))
		url = UrlAgent._wrapWithProxy(url)
		readStream = request.get(url)
		readStream.on "error", callback
		readStream.on "response", (response) ->
			if 200 <= response.statusCode < 300
				FileWriter.writeStreamToDisk project_id, readStream, callback
			else
				error = new UrlFetchFailedError("url fetch failed: #{url}")
				error.statusCode = response.statusCode
				callback(error)

	handleError: (error, req, res, next) ->
		if error instanceof UrlFetchFailedError
			res.status(422).send(
				"Your URL could not be reached (#{error.statusCode} status code). Please check it and try again."
			)
		else if error instanceof InvalidUrlError
			res.status(422).send(
				"Your URL is not valid. Please check it and try again."
			)
		else
			next(error)

	_prependHttpIfNeeded: (url) ->
		if !url.match('://')
			url = 'http://' + url
		return url

	_wrapWithProxy: (url) ->
		# TODO: Consider what to do for Community and Enterprise edition?
		if !Settings.apis?.linkedUrlProxy?.url?
			throw new Error('no linked url proxy configured')
		return "#{Settings.apis.linkedUrlProxy.url}?url=#{encodeURIComponent(url)}"
}
