"use strict";

const required = require("@validatem/required");
const isString = require("@validatem/is-string");
const isInteger = require("@validatem/is-integer");
const isPlainObject = require("@validatem/is-plain-object");

const isEvent = require("../is-event");
const isMatrixID = require("../is-matrix-id");
const isEventID = require("../is-event-id");
const isRoomID = require("../is-room-id");
const optionalObject = require("../optional-object");
const isPaginatedChunkOf = require("../is-paginated-chunk-of");

module.exports = function isRoomEvent(strict = false, extraFields = {}) {
	return isEvent(strict, {
		event_id: [ required, isString ],
		sender: [ required, isMatrixID ],
		origin_server_ts: [ required, isInteger ],
		// In spec, but missing from Room Event format: https://github.com/matrix-org/matrix-doc/issues/2684
		redacts: isEventID, // FIXME: Make required when redaction-type event
		// Spec omission: https://github.com/matrix-org/matrix-doc/issues/2685
		age_ts: isInteger,
		room_id: [ isRoomID ], // FIXME: Not present on /sync, but will need to be required-checked for event validation elsewhere
		// Synapse bug: https://github.com/matrix-org/synapse/issues/7925
		age: isInteger,
		// Synapse bug: https://github.com/matrix-org/synapse/issues/7924
		user_id: isMatrixID,
		// Synapse bug: https://github.com/matrix-org/synapse/issues/7925#issuecomment-662089208
		replaces_state: isEventID,
		// Synapse bug: https://github.com/matrix-org/synapse/issues/7925#issuecomment-663247760
		redacted_because: isPlainObject,
		// Obsolete field originating from a now-defunct Synapse fork running on ponies.im
		origin_server_ipts: [ isInteger ],
		unsigned: optionalObject({
			age: isInteger,
			transaction_id: isString,
			redacted_because: isPlainObject, // FIXME: Cannot do recursion with isRoomEvent (/isStateEvent) -- fixable via `dynamic` wrapper, so that the rules are only generated *after* the validator has finished being declared?
			// Spec omission: https://github.com/matrix-org/matrix-doc/issues/2690
			redacted_by: isEventID,
			// Spec omission: https://github.com/matrix-org/matrix-doc/issues/1167
			replaces_state: isEventID,
			// Spec omission and/or Synapse bug: https://github.com/matrix-org/matrix-doc/issues/877
			prev_content: isPlainObject,
			// Spec omission: https://github.com/matrix-org/matrix-doc/issues/684
			prev_sender: isMatrixID,
			// MSC 1849, not merged yet: https://github.com/matrix-org/matrix-doc/blob/matthew/msc1849/proposals/1849-aggregations.md
			"m.relations": {
				"m.annotation": isPaginatedChunkOf({
					type: [ required, isString ],
					key: [ required, isString ],
					// Should be required according to MSC, but currently missing in Synapse: https://github.com/matrix-org/synapse/issues/7941#issuecomment-663238820
					origin_server_ts: [ /* required, */ isInteger ],
					count: [ required, isInteger ]
				}),
				"m.reference": isPaginatedChunkOf({
					// Should be required according to MSC, but currently missing in Synapse: https://github.com/matrix-org/synapse/issues/7941
					type: [ /* required, */ isString ],
					event_id: [ required, isEventID ]
				}),
				"m.replace": {
					event_id: [ required, isEventID ],
					origin_server_ts: [ required, isInteger ],
					sender: [ required, isMatrixID ]
				}
			}
		}),
		... extraFields
	});
};
