"use strict";

const Promise = require("bluebird");
const path = require("path");
const core = require("../core");
const nodeSass = Promise.promisifyAll(require("node-sass"));
const copyProps = require("copy-props");

const replaceExtension = require("../core/util/replace-extension");
const createSyntaxError = require("../core/errors/syntax-error");

let optionsToCopy = [
	"functions",
	"indentedSyntax",
	"indentType",
	"indentWidth",
	"linefeed",
	"omitSourceMapUrl", // FIXME: outFile stuff
	"outputStyle",
	"precision",
	"sourceComments",
	"sourceMap", // FIXME: outFile stuff
	"sourceMapContents",
	"sourceMapEmbed",
	"sourceMapRoot"
];

module.exports = function (options = {}) {
	return core.createSingleFileTransform({
		displayName: "SCSS (node-sass)",
		// stream: where 'contents' is a stream
		supportsStreams: false,
		// virtual files: files with a contents buffer/stream but without a path
		supportsVirtualFiles: true,
		// virtual filesystem: not-on-disk, eg. for includes of transformed files
		supportsVirtualFilesystem: (options.virtualFilesystemSupport === true),
		transform: ({metadata, contents}) => {
			let includePaths;

			if (!metadata.isVirtual) {
				includePaths = [path.dirname(metadata.path)];
			} else {
				includePaths = [];
			}

			if (options.includePaths != null) {
				includePaths = includePaths.concat(options.includePaths);
			}

			let importer;

			if (options.virtualFilesystemSupport === true && metadata.virtualFilesystem != null) {
				importer = function include(target, previousPath, done) {
					if (/^[a-z]+:/i.test(target)) {
						/* Probably a URL; don't handle this. */
						return null;
					} else {
						return Promise.try(() => {
							return metadata.virtualFilesystem.readFile(target);
						}).then((contents) => {
							done(contents.toString());
						}).catch((err) => {
							done(err);
						});
					}
				};
			}

			return Promise.try(() => {
				let stringContents = contents.toString();

				if (stringContents.length > 0) {
					let renderOptions = {
						data: stringContents,
						includePaths: includePaths,
						importer: importer,
					};

					copyProps(options, renderOptions, optionsToCopy);

					return nodeSass.renderAsync(renderOptions);
				} else {
					return {css: contents};
				}
			}).then((result) => {
				return {
					metadata: {
						/* FIXME: Implement a check that throws errors when a transform returns isVirtual:false for a non-existent path on a non-virtual FS */
						isVirtual: true,
						/* FIXME: Verify that every transform returns a relativePath? */
						relativePath: replaceExtension(metadata.relativePath, "css")
					},
					contents: result.css
				};
			}).catch({status: 1}, (err) => {
				/* Syntax error */
				throw createSyntaxError({
					error: err.message,
					line: err.line,
					column: err.column
				});
			}).catch({status: 3}, (err) => {
				// no input provided
				throw new Error(err.message);
			}).catch((err) => {
				// console.log(require("util").inspect(err, {colors: true, depth: null}));
				throw err;
			}); /* FIXME: Error mapping! */
		}
	});
};
