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

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

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

/**
 * Filters
 */
add_filter( 'bp_rest_notifications_get_items_query_args', __NAMESPACE__ . '\\fetch_all_notifications_from_rest' );
add_filter( 'bp_notifications_get_registered_components', __NAMESPACE__ . '\\register_fake_notification_component' );
add_action( 'rest_api_init', __NAMESPACE__ . '\\register_api_init' );
add_action( 'bp_notification_after_save', __NAMESPACE__ . '\\ping_service', 10, 1 );
add_action( 'bp_notification_after_save', __NAMESPACE__ . '\\update_unseen_count', 10, 1 );
add_filter( 'nisje_register_notification_types', __NAMESPACE__ . '\\map_notification_keys', 9999 );

/**
 * Notifications
 */
function get_notification_types() {
	return apply_filters( 'nisje_register_notification_types', [] );
}

/**
 * Map notification keys.
 *
 * @param array $notifications Registered notifications.
 * @return array
 */
function map_notification_keys( array $notifications ) : array {
	foreach ( $notifications as $index => $notification ) {
		$meta_key = isset( $notification['is_core_bp'] ) && $notification['is_core_bp'] ? $notification['key'] : 'nisje_notification_' . $notification['key'];

		$notifications[ $index ]['key'] = $meta_key;
	}

	return $notifications;
}


/**
 * Populate Notifications
 *
 * @param array $notification Notification.
 */
function enrich_notification_data( array $notification ) : array {
	$action = $notification['action'] ?? '';

	$args = [
		'item_id'           => [],
		'secondary_item_id' => [],
		'community_id'      => nisje_get_setting( 'community_id', 'general' ),
		'message'           => [
			'raw'      => '',
			'rendered' => 'Missing: ' . $action,
		],
	];

	$args = apply_filters( 'nisje_notification_enrich_data', $args, $action, $notification );

	return $args;
}

/**
 * Get notification url based on WP_Post
 *
 * @param WP_Post $item_post Post.
 */
function get_post_url( $item_post ) : string {
	switch ( $item_post->post_type ) {
		case 'nisje-user-content':
			if ( $item_post->post_parent ) {
				return '/groups/' . $item_post->post_parent . '/activity/' . $item_post->ID . '/';
			}

			return '/activity/' . $item_post->ID . '/';

		case 'dekode-news':
			return '/news/' . $item_post->ID . '/';

		case 'nisje-blogs-group':
			return '/groups/' . $item_post->post_parent . '/blogs/' . $item_post->ID . '/';
	}

	return '/';
}

/**
 * Fetch all notifications
 *
 * @param array $args Key value array of query var to query value.
 * @return array
 */
function fetch_all_notifications_from_rest( array $args ) : array {
	$args['is_new'] = 'both';

	return $args;
}

/**
 * Add component
 *
 * @param array $components Components.
 * @return array
 */
function register_fake_notification_component( $components = [] ) {
	if ( ! is_array( $components ) ) {
		$components = [];
	}

	$components[] = 'nisje';

	return $components;
}

/**
 * Extend with custom rest fields.
 *
 * @return void
 */
function register_api_init() {
	bp_rest_register_field( 'notifications', 'enriched_data', [
		'get_callback' => function( $notification ) {
			return enrich_notification_data( $notification );
		},
		'schema'       => [
			'context'     => [ 'view', 'edit' ],
			'description' => esc_html__( 'Enriched Notifications data.', 'nisje' ),
			'readonly'    => true,
			'type'        => 'array',
		],
	] );

	bp_rest_register_field( 'notifications', 'community_id', [
		'get_callback' => function( $notification ) {
			return nisje_get_setting( 'community_id', 'general' );
		},
		'schema'       => [
			'context'     => [ 'view', 'edit' ],
			'description' => esc_html__( 'Community Key', 'nisje' ),
			'type'        => 'string',
			'readonly'    => true,
		],
	] );

	// Notification settings.
	register_rest_field( 'user', 'notificationSettings', [
		'get_callback'    => function ( $object ) {
			$retval        = [];
			$notifications = get_notification_types();

			foreach ( $notifications as $notification ) {
				$retval[] = [
					'description' => $notification['description'],
					'key'         => $notification['key'],
					'label'       => $notification['label'],
					'type'        => $notification['type'] ?? '',
					'is_core_bp'  => $notification['is_core_bp'] ?? false,
					'value'       => ( 'yes' === get_user_meta( absint( $object['id'] ), $notification['key'], true ) ) ? 1 : 0,
				];
			}

			return $retval;
		},
		'update_callback' => function ( $field, $object ) {
			if ( is_array( $field ) && $object instanceof \WP_User ) {
				foreach ( $field as $key => $value ) {
					$value = ( 1 === $value ) ? 'yes' : 'no';

					update_user_meta( intval( $object->data->ID ), $key, $value );
				}
			}
		},
		'scheme'          => [
			'context'     => [ 'view', 'edit' ],
			'description' => esc_html__( 'Notification settings.', 'nisje' ),
			'type'        => 'array',
			'items'       => [
				'type' => 'object',
			],
			'readonly'    => true,
		],
	] );
}

/**
 * Check if ping service is enabled
 */
function is_ping_service_enabled() {
	$is_enabled = defined( 'NISJE_DEV_NOTIFICATIONS' ) || ( defined( 'WP_ENV' ) && 'production' === WP_ENV );
	$is_enabled = apply_filters( 'nisje_notification_ping_service_enabled', $is_enabled );

	return $is_enabled;
}

/**
 * Ping Service after notification is saved.
 *
 * @param \BP_Notifications_Notification $notification Notification.
 */
function ping_service( \BP_Notifications_Notification $notification ) {
	if ( ! is_ping_service_enabled() ) {
		return;
	}

	$notification_data = [
		'id'                => $notification->id,
		'user_id'           => $notification->user_id,
		'item_id'           => $notification->item_id,
		'secondary_item_id' => $notification->secondary_item_id,
		'component'         => $notification->component_name,
		'action'            => $notification->component_action,
		'date'              => \bp_rest_prepare_date_response( $notification->date_notified ),
		'is_new'            => $notification->is_new,
	];

	$notification_data['enriched_data'] = enrich_notification_data( $notification_data );

	$url   = defined( 'NISJE_NOTIFICATIONS_URL' ) ? NISJE_NOTIFICATIONS_URL : 'https://notifications.nisje.app/api/v1/bp-notification';
	$token = defined( 'NISJE_NOTIFICATIONS_TOKEN' ) ? NISJE_NOTIFICATIONS_TOKEN : '';

	$args = [
		'url'  => $url,
		'body' => [
			'token'        => $token,
			'notification' => $notification_data,
		],
	];

	$args = (array) apply_filters( 'nisje_notification_ping_service', $args );
	if ( ! isset( $args['url'], $args['body'] ) ) {
		return;
	}

	$body = $args['body'];
	if ( empty( $body['token'] ) || ! is_array( $body['notification'] ) ) {
		return;
	}

	$body = [
		'headers' => [
			'Accept'       => 'application/json',
			'Content-Type' => 'application/json',
		],
		'body'    => wp_json_encode( $body ),
	];

	wp_remote_post( $args['url'], $body );
}

/**
 * Set unseen count to user meta
 *
 * @param \BP_Notifications_Notification $notification Notification.
 */
function update_unseen_count( \BP_Notifications_Notification $notification ) {
	$count = get_user_meta( (int) $notification->user_id, 'notifications_unseen', true ) ?: 0;
	update_user_meta( (int) $notification->user_id, 'notifications_unseen', $count + 1 );
}

/**
 * Check user notification setting.
 *
 * @param int    $user_id The ID of the user to be checked (IE '1').
 * @param string $notification_key Notification type key (IE 'reaction').
 *
 * @return boolean
 */
function is_notification_active( $user_id, $notification_key ) {
	// We need a key and it needs to be in the notification types array.
	if ( ! $notification_key || ! in_array( $notification_key, array_column( get_notification_types(), 'key' ), true ) ) {
		return false;
	}

	// We need a user id.
	if ( ! $user_id ) {
		return false;
	}

	return get_user_meta( intval( $user_id ), $notification_key, true );
}
