<?php
/**
 * Comments
 *
 * @package Nisje
 */

declare( strict_types = 1 );
namespace Nisje\Comments;

defined( 'ABSPATH' ) || die( 'This is Nisje!' );

/**
 * Filters
 */
add_filter( 'comment_text', 'do_shortcode' );
add_filter( 'option_comment_whitelist', __NAMESPACE__ . '\\whitelist_all_users', 10, 1 );
add_action( 'rest_api_init', __NAMESPACE__ . '\\register_api_init' );
add_filter( 'rest_request_before_callbacks', __NAMESPACE__ . '\\allow_deleting_own_comments', 10, 3 );
add_filter( 'nisje_notification_enrich_data', __NAMESPACE__ . '\\enrich_notification_data', 10, 3 );

// Notifications.
add_filter( 'nisje_register_notification_types', __NAMESPACE__ . '\\register_notifications' );
add_action( 'rest_insert_comment', __NAMESPACE__ . '\\new_comment_notification', 10, 3 );

/**
 * Whitelist all users. No need to have a previously approved comment.
 * Option: Comment author must have a previously approved comment
 *
 * @param int $value Current value.
 * @return int Always off.
 */
function whitelist_all_users( $value ) { // phpcs:ignore
	return 0;
}

/**
 * Extend with custom rest fields.
 *
 * @return void
 */
function register_api_init() {
	// Reactions.
	register_rest_field( 'comment', 'reactions', [
		'get_callback' => function ( $object ) {
			return nisje_get_user_reactions( $object['id'], 'comment' );
		},
		'schema'       => [
			'context'     => [ 'view', 'edit' ],
			'description' => esc_html__( 'Reactions', 'nisje' ),
			'type'        => 'array',
			'items'       => [
				'type' => 'mixed',
			],
			'readonly'    => true,
		],
	] );

	// User ID.
	register_rest_field( 'comment', 'user_id', [
		'get_callback' => function ( $object ) {
			return absint( $object['author'] );
		},
		'schema'       => [
			'context'     => [ 'view' ],
			'description' => esc_html__( 'The user ID of the author of the comment.', 'nisje' ),
			'type'        => 'integer',
			'readonly'    => true,
		],
	] );
}

/**
 * Check request.
 *
 * @param WP_HTTP_Response|WP_Error $response Result to send to the client. Usually a WP_REST_Response or WP_Error.
 * @param array                     $handler  Route handler used for the request.
 * @param WP_REST_Request           $request  Request used to generate the response.
 */
function allow_deleting_own_comments( $response, $handler, $request ) { // phpcs:ignore
	if ( 'DELETE' === $request->get_method() && strpos( $request->get_route(), '/wp/v2/comments/' ) !== false ) {
		add_filter( 'map_meta_cap', function( $caps, $cap, $user_id, $args ) { // phpcs:ignore
			if ( in_array( $cap, [ 'moderate_comments', 'edit_comment' ], true ) ) {
				if ( ! is_user_logged_in() ) {
					return [ 'do_not_allow' ];
				}

				if ( 'edit_comment' === $cap ) {
					$comment = get_comment( $args[0] );
					if ( is_a( $comment, 'WP_Comment' ) ) {
						if ( (int) $comment->user_id === (int) $user_id ) {
							return [];
						} else {
							return [ 'do_not_allow' ];
						}
					}
				} elseif ( 'moderate_comments' === $cap ) {
					return [];
				}
			}

			return $caps;
		}, 10, 4 );
	}

	return $response;
}

/**
 * Populate Notifications
 *
 * @param array  $args         Arguments.
 * @param string $action       Action.
 * @param array  $notification Arguments.
 */
function enrich_notification_data( array $args, string $action, array $notification ) : array {
	if ( 'new_comment' === $action ) {
		$args['item_id'] = bp_core_get_user_displayname( $notification['item_id'] );

		$post = get_post( $notification['secondary_item_id'] );
		if ( $post instanceof \WP_Post ) {
			$args['secondary_item_id'] = wp_strip_all_tags( get_the_title( $post->ID ) );
			$args['href']              = \Nisje\Nofications\get_post_url( $post );

			if ( 50 < strlen( $args['secondary_item_id'] ) ) {
				$args['secondary_item_id'] = preg_replace( '/\s+?(\S+)?$/', '', substr( $args['secondary_item_id'], 0, 50 ) ) . '...';
			}
		}

		if ( $post->post_parent ) {
			$group_name = '';

			$group = nisje_get_group( $post->post_parent );
			if ( ! is_wp_error( $group ) ) {
				$group_name = $group->name;
			}

			// translators: %1$s author, %2$s post, %3$s groupname.
			$raw      = __( '%1$s added a new comment to the post "%2$s" in the group %3$s', 'nisje' );
			$rendered = sprintf( esc_html( $raw ),
				'<strong>' . $args['item_id'] . '</strong>',
				$args['secondary_item_id'],
				$group_name
			);
		} else {
			// translators: %1$s author, %2$s post.
			$raw      = __( '%1$s added a new comment to the post "%2$s"', 'nisje' );
			$rendered = sprintf( esc_html( $raw ),
				'<strong>' . $args['item_id'] . '</strong>',
				$args['secondary_item_id']
			);
		}

		$args['avatar']  = $notification['item_id'];
		$args['message'] = [
			'raw'      => $raw,
			'rendered' => $rendered,
		];
	}

	return $args;
}

/**
 * Register notifications.
 *
 * @param array $notifications Registered notifications.
 * @return array
 */
function register_notifications( array $notifications ) : array {
	$notifications[] = [
		'key'         => 'new_comment',
		'label'       => esc_html__( 'New comment', 'nisje' ),
		'description' => esc_html__( 'When someone posts a new comment to a post', 'nisje' ) . ' - App',
	];

	$notifications[] = [
		'key'         => 'email_new_comment',
		'label'       => esc_html__( 'New comment', 'nisje' ),
		'description' => esc_html__( 'When someone posts a new comment to a post', 'nisje' ) . ' - ' . esc_html__( 'E-mail notification', 'nisje' ),
		'type'        => 'email',
		'is_core_bp'  => false,
	];

	return $notifications;
}

/**
 * Register comment notification
 *
 * @param WP_Comment      $comment  Inserted or updated comment object.
 * @param WP_REST_Request $request  Request object.
 * @param bool            $creating True when creating a comment, false when updating.
 */
function new_comment_notification( $comment, $request, $creating ) {
	if ( $creating ) {
		// Grab the post we are attaching a comment to.
		$post = get_post( $comment->comment_post_ID );

		$feeds = [];

		// Get all comments on this post (including the current one).
		$post_comments = get_comments( [
			'post_id' => $post->ID,
		] );

		// If there is at least 1 comment.
		if ( $post_comments && 0 < count( $post_comments ) ) {
			// If the comment author is not the post author (never notify yourself when commenting on your own post).
			if ( intval( $post->post_author ) !== intval( $comment->user_id ) ) {
				$feeds[] = $post->post_author;
			}

			// For each post comment add author feed to the feeds list.
			foreach ( $post_comments as $post_comment ) {
				// If the current comment author is not the current user.
				if ( get_current_user_id() !== intval( $post_comment->user_id ) ) {
					$feeds[] = $post_comment->user_id;
				}
			}

			foreach ( array_unique( $feeds ) as $feed ) {
				if ( \Nisje\Nofications\is_notification_active( $feed, 'nisje_notification_new_comment' ) ) {
					bp_notifications_add_notification( [
						'user_id'           => $feed,
						'item_id'           => $comment->user_id,
						'secondary_item_id' => $post->ID,
						'component_name'    => 'nisje',
						'component_action'  => 'new_comment',
						'date_notified'     => bp_core_current_time(),
						'is_new'            => 1,
					] );
				}

				if ( \Nisje\Nofications\is_notification_active( $feed, 'nisje_notification_email_new_comment' ) ) {
					$user = get_user_by( 'id', $feed );

					$author = get_userdata( $comment->user_id );

					$group_name = '';

					if ( $post->post_parent ) {
						$url   = sprintf( '/groups/%1$s/activity/%2$s/', $post->post_parent, $post->ID );
						$group = nisje_get_group( $post->post_parent );
						if ( ! is_wp_error( $group ) ) {
							// translators: %s in the group notification.
							$group_name = sprintf( esc_html__( ' in the group "%s"', 'nisje' ), $group->name );
						}
					} else {
						$url = sprintf( '/activity/%s/', $post->ID );
					}

					$args = [
						'tokens' => [
							'comment.id'                => $comment->comment_ID,
							'commenter.id'              => $comment->user_id,
							'usermessage'               => wp_strip_all_tags( $comment->comment_content ),
							'original_activity.user_id' => $feed,
							'group.name'                => $group_name,
							'poster.name'               => $author->display_name,
							'thread.url'                => esc_url( home_url( $url ) ),
							'unsubscribe'               => '',
						],
					];

					bp_send_email( 'activity-comment', $user->user_email, $args );
				}
			}
		}
	}
}
