"use strict";

const defaultValue = require("default-value");
const numberDerivedEvents = require("../number-derived-events");

function mapLevels(eventContent) {
	if (eventContent != null) {
		return {
			defaultRequiredPowerLevels: {
				stateChange: defaultValue(eventContent.state_default, 50),
				message: defaultValue(eventContent.events_default, 0),
			},
			requiredPowerLevels: {
				kick: defaultValue(eventContent.kick, 50),
				ban: defaultValue(eventContent.ban, 50),
				invite: defaultValue(eventContent.invite, 50),
				redact: defaultValue(eventContent.redact, 50)
			},
			requiredEventPowerLevels: eventContent.events,
			requiredNotificationPowerLevels: { room: 50, ... eventContent.notifications },
			defaultUserPowerLevel: defaultValue(eventContent.users_default, 0),
			currentPowerLevels: eventContent.users
		};
	} else {
		return {
			defaultRequiredPowerLevels: {
				stateChange: 0,
				message: 0,
			},
			requiredPowerLevels: {
				kick: 50,
				ban: 50,
				invite: 50,
				redact: 50
			},
			requiredEventPowerLevels: {},
			requiredNotificationPowerLevels: {
				room: 50
			},
			defaultUserPowerLevel: 0,
			currentPowerLevels: {}
		};
	}
}

// FIXME: Option for parsing as a whole, rather than as a diff? Maybe package `mapLevels` as a separate `map-power-levels-event-full` package or so?
// FIXME: Do above + emit as a whole event, for later use in powerlevel-modifying event creation; same for ACLs (maybe build an abstraction for automatically tracking this stuff internally?) -- and make sure to document that the user should use either the full event OR the derived event, not both, for the same purpose!
module.exports = function mapPowerLevelsEvent(event, _context) {
	let oldState = mapLevels(event.unsigned.prev_content);
	let newState = mapLevels(event.content);

	let deltaEvents = [];

	if (oldState.defaultUserPowerLevel !== newState.defaultUserPowerLevel) {
		deltaEvents.push({
			type: "defaultUserPowerLevelChanged",
			sender: event.sender,
			oldLevel: oldState.defaultUserPowerLevel,
			newLevel: newState.defaultUserPowerLevel
		});
	}

	for (let [ eventCategory, newLevel ] of Object.entries(newState.defaultRequiredPowerLevels)) {
		let oldLevel = oldState.defaultRequiredPowerLevels[eventCategory];

		if (newLevel !== oldLevel) {
			deltaEvents.push({
				type: "defaultRequiredPowerLevelChanged",
				sender: event.sender,
				eventCategory: eventCategory,
				newLevel: newLevel,
				oldLevel: oldLevel
			});
		}
	}

	for (let [ action, newLevel ] of Object.entries(newState.requiredPowerLevels)) {
		let oldLevel = oldState.requiredPowerLevels[action];

		if (newLevel !== oldLevel) {
			deltaEvents.push({
				type: "requiredPowerLevelChanged",
				sender: event.sender,
				action: action,
				newLevel: newLevel,
				oldLevel: oldLevel
			});
		}
	}

	for (let [ eventType, newLevel ] of Object.entries(newState.requiredEventPowerLevels)) {
		let oldLevel = oldState.requiredEventPowerLevels[eventType]; // FIXME: Default power level?

		if (newLevel !== oldLevel) {
			deltaEvents.push({
				type: "requiredEventPowerLevelChanged",
				sender: event.sender,
				eventType: eventType,
				newLevel: newLevel,
				oldLevel: oldLevel
			});
		}
	}

	for (let [ notificationType, newLevel ] of Object.entries(newState.requiredNotificationPowerLevels)) {
		let oldLevel = oldState.requiredNotificationPowerLevels[notificationType];

		if (newLevel !== oldLevel) {
			deltaEvents.push({
				type: "requiredNotificationPowerLevelChanged",
				sender: event.sender,
				notificationType: notificationType,
				newLevel: newLevel,
				oldLevel: oldLevel
			});
		}
	}

	for (let [ matrixID, newLevel ] of Object.entries(newState.currentPowerLevels)) {
		let oldLevel = oldState.currentPowerLevels[matrixID];

		if (newLevel !== oldLevel) {
			deltaEvents.push({
				type: "userPowerLevelChanged",
				sender: event.sender,
				user: matrixID,
				newLevel: defaultValue(newLevel, newState.defaultUserPowerLevel),
				oldLevel: defaultValue(oldLevel, oldState.defaultUserPowerLevel),
				newLevelIsExplicit: (newLevel != null),
				oldLevelIsExplicit: (oldLevel != null)
			});
		}
	}

	numberDerivedEvents(event.event_id, deltaEvents);

	return deltaEvents;
};
