const Logger = require('@joplin/lib/Logger').default;
const { netUtils } = require('@joplin/lib/net-utils.js');

const http = require('http');
const urlParser = require('url');
const enableServerDestroy = require('server-destroy');

class ResourceServer {
	constructor() {
		this.server_ = null;
		this.logger_ = new Logger();
		this.port_ = null;
		this.linkHandler_ = null;
		this.started_ = false;
	}

	setLogger(logger) {
		this.logger_ = logger;
	}

	logger() {
		return this.logger_;
	}

	started() {
		return this.started_;
	}

	baseUrl() {
		if (!this.port_) return '';
		return `http://127.0.0.1:${this.port_}`;
	}

	setLinkHandler(handler) {
		this.linkHandler_ = handler;
	}

	async start() {
		this.port_ = await netUtils.findAvailablePort([9167, 9267, 8167, 8267]);
		if (!this.port_) {
			this.logger().error('Could not find available port to start resource server. Please report the error at https://github.com/laurent22/joplin');
			return;
		}

		this.server_ = http.createServer();

		this.server_.on('request', async (request, response) => {
			const writeResponse = message => {
				response.write(message);
				response.end();
			};

			const url = urlParser.parse(request.url, true);
			let resourceId = url.pathname.split('/');
			if (resourceId.length < 2) {
				writeResponse(`Error: could not get resource ID from path name: ${url.pathname}`);
				return;
			}
			resourceId = resourceId[1];

			if (!this.linkHandler_) throw new Error('No link handler is defined');

			try {
				const done = await this.linkHandler_(resourceId, response);
				if (!done) throw new Error(`Unhandled resource: ${resourceId}`);
			} catch (error) {
				response.setHeader('Content-Type', 'text/plain');
				// eslint-disable-next-line require-atomic-updates
				response.statusCode = 400;
				response.write(error.message);
			}

			response.end();
		});

		this.server_.on('error', error => {
			this.logger().error('Resource server:', error);
		});

		this.server_.listen(this.port_);

		enableServerDestroy(this.server_);

		this.started_ = true;
	}

	stop() {
		if (this.server_) this.server_.destroy();
		this.server_ = null;
	}
}

module.exports = ResourceServer;