/* jslint node: true, esnext: true */

"use strict";

const path = require('path'),
	route = require('koa-route'),
	step = require('kronos-step'),
	ReadableStream = require('stream').Readable,
	FormData = require('form-data'),
	endpoint = require('kronos-endpoint');

/**
 * Endpoint to link against a koa route
 */
class RouteSendEndpoint extends endpoint.SendEndpoint {

	/**
	 * @param name {String} endpoint name
	 * @param owner {Step} the owner of the endpoint
	 * @param method {String} http method defaults to get
	 * @param content
	 */
	constructor(name, owner, path, method, content, serviceName) {
		super(name, owner);

		// The path in the URL
		Object.defineProperty(this, 'path', {
			value: path
		});

		method = method ? method.toLowerCase() : "get";

		// The HTTP method to use (GET, POST, ...)
		Object.defineProperty(this, 'method', {
			value: method
		});

		// The path in the URL
		Object.defineProperty(this, 'serviceName', {
			value: serviceName
		});
	}


	/**
	 *
	 */
	get route() {
		if (!this._route) {
			this._route = route[this.method](this.path, ctx => {

				this.owner.info(`${this.method} ${this.path}`);

				const message = {
					"info": {
						"request": ctx.request,
					},
					"payload": ctx.req
				};

				return this.receive(message).then(response => {
					//this.owner.info(`${this.method} ${this.path}: ${JSON.stringify(response)}`);
					this.owner.info(`${this.method} ${this.path}`);

					if (response.payload && response.payload.readable) {
						ctx.set('content-type', response.payload.getHeaders()["content-type"]);
						ctx.body = response.payload;
					} else {
						ctx.body = response;
					}

				});
			});
		}
		return this._route;
	}

	toString() {
		return `${this.method} ${this.name}`;
	}
}

const httpRoutingStep = Object.assign({}, step.Step, {
	"name": "kronos-http-routing",
	"description": "routes http requests to endpoints",
	initialize(manager, name, conf, props) {
		props._listener = {
			value: conf.listener || 'default-listener'
		};
	},

	_start() {
		// wait until names service is present
		return this.manager.declareService({
			'type': 'koa',
			'name': this._listener
		}, true).then(service => {
			this.listener = service;

			const registry = this.manager.services.registry;

			for (let en in this.endpoints) {
				const ep = this.endpoints[en];
				const route = ep.route;

				if (route) {
					service.koa.use(route);

					if (registry && ep.serviceName) {
						registry.registerService(ep.serviceName, {
							url: path.join(this.listener.url, route.path)
						});
					}
				}
			}

			return service.start();
		});
	},

	_stop() {
		const registry = this.manager.services.registry;

		for (let en in this.endpoints) {
			const ep = this.endpoints[en];
			const route = ep.route;
			if (route) {
				if (registry && ep.serviceName) {
					registry.unregisterService(ep.serviceName, {
						url: path.join(this.listener.url, route.path)
					});
				}

				this.trace(level => `removing route ${this.endpoints[en]}`);
				this.listener.koa.delete(route);
			}
		}
		return Promise.resolve();
	},

	createEndpoints(def) {
		for (let name in def.endpoints) {
			const r = def.endpoints[name];

			const ep = new RouteSendEndpoint(name, this, r.path || name, r.method, r.serviceName);

			if (r.interceptors) {
				ep.interceptors = r.interceptors.map(icDef => this.manager.createInterceptorInstanceFromConfig(icDef, ep));
			}

			this.addEndpoint(ep);
		}
	}
});

exports.registerWithManager = manager => manager.registerStep(httpRoutingStep);

@@ -144,88 +144,8 @@
 '),%0A
-%09ReadableStream = require('stream').Readable,%0A%09FormData = require('form-data'),%0A
 %09end
@@ -799,33 +799,8 @@
 );%0A%0A
-%09%09// The path in the URL%0A
 %09%09Ob
@@ -874,17 +874,16 @@
 %7D);%0A%09%7D%0A%0A
-%0A
 %09/**%0A%09 *
@@ -981,17 +981,16 @@
 tx =%3E %7B%0A
-%0A
 %09%09%09%09this
@@ -1042,24 +1042,28 @@
 %09%09%09%09
-const message = 
+return this.receive(
 %7B%0A%09%09
@@ -1146,146 +1146,28 @@
 %09%09%09%7D
-;%0A%0A%09%09%09%09return this.receive(message).then(response =%3E %7B%0A%09%09%09%09%09//this.owner.info(%60$%7Bthis.method%7D $%7Bthis.path%7D: $%7BJSON.stringify(response)%7D%60);
+).then(response =%3E %7B
 %0A%09%09%09
@@ -1432,25 +1432,24 @@
 nse;%0A%09%09%09%09%09%7D%0A
-%0A
 %09%09%09%09%7D);%0A%09%09%09%7D
@@ -2897,89 +2897,22 @@
 oint
-s(def) %7B%0A%09%09for (let 
+(
 name
- in
+,
  def
-.endpoints) %7B%0A%09%09%09const r = def.endpoints%5Bname%5D;%0A%0A%09
+) %7B%0A
 %09%09co
@@ -2954,17 +2954,19 @@
 , this, 
-r
+def
 .path %7C%7C
@@ -2972,17 +2972,19 @@
 %7C name, 
-r
+def
 .method,
@@ -2984,17 +2984,19 @@
 method, 
-r
+def
 .service
@@ -3004,23 +3004,49 @@
 ame);%0A%0A%09
+%09this.addEndpoint(ep);%0A%0A
 %09%09if (
-r
+def
 .interce
@@ -3057,17 +3057,16 @@
 s) %7B%0A%09%09%09
-%09
 ep.inter
@@ -3075,17 +3075,19 @@
 ptors = 
-r
+def
 .interce
@@ -3171,39 +3171,8 @@
 ));%0A
-%09%09%09%7D%0A%0A%09%09%09this.addEndpoint(ep);%0A
 %09%09%7D%0A

remove unused require() refactor: use createEndpoint(name,def) instead of createEndpoint(def)