"use strict";
const DEFAULT_OPTIONS = require("./defaultOptions");
const evaluateValue = require("evaluate-value");
const list2Array = require("list-to-array");
const parseMetaRefresh = require("http-equiv-refresh");
const parseSrcset = require("parse-srcset");

const CONTENT_ATTR = "content";
const PING_ATTR = "ping";
const SRCSET_ATTR = "srcset";

const DELIMITER = ",";
const EMPTY_STRING = "";
const EMPTY_TAG_GROUP = Object.freeze({});
const FUNCTION_TYPE = "function";
const PRETTY_DELIMITER = ", ";



const plugin = options =>
{
	const {eachURL, filter} = Object.assign({}, DEFAULT_OPTIONS, options);

	if (typeof eachURL !== FUNCTION_TYPE)
	{
		throw new TypeError("eachURL option must be a function");
	}

	// const tagMatchers = Object.keys(filter).map(tagName => ({ tag: tagName }));

	// Called by PostHTML
	return tree =>
	{
		const promises = [];

		tree.walk(node =>
		// tree.match(tagMatchers, (node) =>
		{
			if (node.attrs === undefined) {
				return node;
			}

			const tagGroup = filter[node.tag] || EMPTY_TAG_GROUP;

			Object.keys(node.attrs).forEach(attrName =>
			{
				const isAcceptedTagAttr = attrName in tagGroup && evaluateValue(tagGroup[attrName], node, attrName);

				if (isAcceptedTagAttr)
				{
					switch (attrName)
					{
						case CONTENT_ATTR:
						{
							promises.push( transformMetaRefresh(node, attrName, eachURL) );
							break;
						}
						case PING_ATTR:
						{
							promises.push( transformCommaSeparated(node, attrName, eachURL) );
							break;
						}
						case SRCSET_ATTR:
						{
							promises.push( transformSrcset(node, attrName, eachURL) );
							break;
						}
						default:
						{
							promises.push( transformDefault(node, attrName, eachURL) );
						}
					}
				}
			});

			return node;
		});

		return Promise.all(promises).then(() => tree);
	};
};



const transformCommaSeparated = ({attrs, tag}, attrName, transformer) =>
{
	const urls = list2Array( attrs[attrName], DELIMITER );

	if (urls.length > 0)
	{
		const promises = urls.map(value => Promise.resolve( transformer(value, attrName, tag) ));

		return Promise.all(promises).then(newUrls => attrs[attrName] = newUrls.join(PRETTY_DELIMITER));
	}
};



const transformDefault = ({attrs, tag}, attrName, transformer) =>
{
	return Promise.resolve( transformer( attrs[attrName], attrName, tag ) )
	.then(newUrl => attrs[attrName] = newUrl);
};



const transformMetaRefresh = ({attrs, tag}, attrName, transformer) =>
{
	const {timeout, url} = parseMetaRefresh( attrs[attrName] );

	if (timeout !== null)
	{
		return Promise.resolve( transformer(url || "", attrName, tag) )
		.then(newUrl => attrs[attrName] = `${timeout}; url=${newUrl}`);
	}
};



const transformSrcset = ({attrs, tag}, attrName, transformer) =>
{
	const values = parseSrcset( attrs[attrName] );

	if (values.length > 0)
	{
		const promises = values.map(({d, h, url, w}) => Promise.resolve( transformer(url, attrName, tag) )
		.then(newUrl =>
		{
			d = d !== undefined ? ` ${d}x` : EMPTY_STRING;
			h = h !== undefined ? ` ${h}h` : EMPTY_STRING;
			w = w !== undefined ? ` ${w}w` : EMPTY_STRING;

			return `${newUrl}${w}${h}${d}`;
		}));

		return Promise.all(promises).then(newValues => attrs[attrName] = newValues.join(PRETTY_DELIMITER));
	}
};



module.exports = plugin;
