'use strict';

const camelCase = require('./camel-case');
const Stringifier = require('postcss/lib/stringifier');

class ObjectStringifier extends Stringifier {
	object(node) {
		this.builder('{', node, 'start');

		let after;

		if (node.nodes && node.nodes.length) {
			this.body(node);
			after = this.raw(node, 'after');
		} else {
			after = this.raw(node, 'after', 'emptyBody');
		}

		if (after) this.builder(after);

		this.builder('}', node, 'end');
	}
	literal(node, semicolon) {
		this.builder(node.text + (semicolon ? ',' : ''), node);
	}
	decl(node, semicolon) {
		let prop = this.rawValue(node, 'prop');

		if (prop === 'float') {
			prop = 'cssFloat';
		}

		let string = prop;

		const isObjectShorthand = node.raws.node && node.raws.node.shorthand;

		if (!isObjectShorthand) {
			const between = this.raw(node, 'between', 'colon');
			const value = this.rawValue(node, 'value');

			string += between + value;
		}

		if (semicolon) string += ',';

		this.builder(string, node);
	}
	rule(node, semicolon) {
		this.block(node, this.rawValue(node, 'selector'), semicolon);
	}
	atrule(node, semicolon) {
		const name = this.rawValue(node, 'name');
		const params = this.rawValue(node, 'params');

		if (node.nodes) {
			let string;

			if (params) {
				const afterName = this.raw(node, 'afterName');

				string = name + afterName + params;
			} else {
				string = name;
			}

			this.block(node, string, semicolon);
		} else {
			const between = this.raw(node, 'between', 'colon');
			let string = name + between + params;

			if (semicolon) string += ',';

			this.builder(string, node);
		}
	}
	block(node, start, semicolon) {
		super.block(node, start);

		if (semicolon) {
			this.builder(',', node);
		}
	}
	comment(node) {
		const left = this.raw(node, 'left', 'commentLeft');
		const right = this.raw(node, 'right', 'commentRight');

		if (node.raws.inline) {
			const text = node.raws.text || node.text;

			this.builder('//' + left + text + right, node);
		} else {
			this.builder('/*' + left + node.text + right + '*/', node);
		}
	}
	raw(node, own, detect) {
		let value = super.raw(node, own, detect);

		if (
			(own === 'between' || (own === 'afterName' && node.type === 'atrule' && !node.nodes)) &&
			!/:/.test(value)
		) {
			value = ':' + value;
		} else if (own === 'before' && /^(decl|rule)$/.test(node.type)) {
			value = value.replace(/\S+$/, '');
		}

		return value;
	}
	rawValue(node, prop) {
		const raw = node.raws[prop];

		if (raw) {
			const descriptor = Object.getOwnPropertyDescriptor(raw, 'raw');

			if (descriptor && descriptor.get) {
				return raw.prefix + raw.raw + raw.suffix;
			}
		}

		let value = super.rawValue(node, prop);

		if (value === null || value === undefined) {
			return value;
		}

		if (/^(prop|selector)$/i.test(prop)) {
			value = camelCase(value);

			if (node.raws.before && /(\S+)$/.test(node.raws.before)) {
				value = RegExp.$1 + value;
			} else if (value && !/\W/.test(value)) {
				return value;
			}
		} else if (node.type === 'atrule') {
			if (prop === 'name') {
				value = '@' + value;
			} else if (node.nodes) {
				return;
			}

			if (node.nodes) {
				value += this.raw(node, 'afterName');
				value += super.rawValue(node, 'params');
			}
		}

		value = JSON.stringify(value);

		return value;
	}
}

module.exports = ObjectStringifier;