<?php

namespace GemBoards\API;

use GemBoards\Classes\Exception\GemboardsInvalidArgumentException;
use GemBoards\Collections\NotifiedUserCollection;
use GemBoards\Entities\NotifiedUser;
use GemBoards\Utils\Helper;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Server;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Notification extends WP_REST_Controller {

	public static function init() {
		$self            = new self();
		$self->namespace = 'gemboards/v1';
		$self->rest_base = 'notifications';
		add_action( 'rest_api_init', [ $self, 'register_routes' ] );
	}

	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_items' ],
				'permission_callback' => function () {
					if ( ! current_user_can( 'read' ) ) {
						return new WP_Error(
							'rest_forbidden_context',
							esc_html__( 'Sorry, you are not allowed to access this API.', 'gemboards' ),
							array( 'status' => rest_authorization_required_code() )
						);
					}

					return true;
				},
				'args'                => [
					'page'     => [
						'type'        => 'integer',
						'required'    => false,
						'default'     => 1,
						'description' => __( 'Page number', 'gemboards' ),
					],
					'per_page' => [
						'type'        => 'integer',
						'required'    => false,
						'default'     => 10,
						'description' => __( 'Per Page number', 'gemboards' ),
					],
				],
			],
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/mark_as_read',
			[
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => [ $this, 'mark_all_as_read' ],
				'permission_callback' => function () {
					if ( ! current_user_can( 'read' ) ) {
						return new WP_Error(
							'rest_forbidden_context',
							esc_html__( 'Sorry, you are not allowed to access this API.', 'gemboards' ),
							array( 'status' => rest_authorization_required_code() )
						);
					}

					return true;
				},
				'args'                => [],
			],
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>\d+)',
			[
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => [ $this, 'mark_as_read' ],
				'permission_callback' => function () {
					if ( ! current_user_can( 'read' ) ) {
						return new WP_Error(
							'rest_forbidden_context',
							esc_html__( 'Sorry, you are not allowed to access this API.', 'gemboards' ),
							array( 'status' => rest_authorization_required_code() )
						);
					}

					return true;
				},
				'args'                => [
					'id' => [
						'type'        => 'integer',
						'required'    => true,
						'description' => __( 'Notification ID', 'gemboards' ),
					],
				],
			],
		);
	}

	public function get_items( $request ) {
		$per_page = $request->get_param( 'per_page' );
		$page     = $request->get_param( 'page' );

		$cache_group            = 'gemboards_notifications';
		$cache_key_last_changed = wp_cache_get_last_changed( $cache_group );
		$cache_key              = "get_notifications_{$cache_key_last_changed}:$per_page:$page";
		$has_cache              = wp_cache_get( $cache_key, $cache_group );
		if ( false !== $has_cache ) {
			return rest_ensure_response( $has_cache );
		}

		$user_id = get_current_user_id();
		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$notifications = $wpdb->get_results(
			$wpdb->prepare("SELECT n.*, c.id AS card_id, p.post_title AS card_title, b.id AS board_id FROM
					{$wpdb->prefix}gemboards_notifications n
					INNER JOIN {$wpdb->prefix}gemboards_notified_users nu ON nu.notification_id = n.id AND nu.to_user_id = %d
					INNER JOIN {$wpdb->prefix}gemboards_cards c ON c.task_id = n.object_id
					INNER JOIN {$wpdb->prefix}posts p ON c.task_id = p.ID
					INNER JOIN {$wpdb->prefix}gemboards_boards b ON b.id = c.board_id
					INNER JOIN {$wpdb->prefix}gemboards_roles r ON r.object_id = b.project_id
					AND r.object_type = 'project'
					AND r.user_id = %d
				WHERE
					n.object_type = 'task'
				LIMIT %d, %d", $user_id, $user_id, ( $page - 1 ) * $per_page, $per_page )
		);
		// phpcs:enable
		$result = [
			'pagination' => [
				'per_page' => $request->get_param( 'per_page' ),
				'page'     => $request->get_param( 'page' ),
			],
			'data'       => $notifications,
		];
		wp_cache_set( $cache_key, $result, $cache_group );

		return rest_ensure_response( $result );
	}

	public function mark_all_as_read() {
		try {
			$has_notified_users = ( new NotifiedUserCollection( [
				'per_page' => - 1,
				'fields'   => 'count',
				'where'    => [
					[
						'key'   => 'to_user_id',
						'value' => get_current_user_id(),
					],
					[
						'key'   => 'is_read',
						'value' => 0,
					],
				],
			] ) )->get_results();
			$has_notified_users = ! empty($has_notified_users) ? $has_notified_users[0] : 0;
			// If no unread notifications, return success without clearing the cache.
			if ( ! $has_notified_users ) {
				return rest_ensure_response( [
					'success' => true,
				] );
			}
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( esc_html($e->getMessage()) );
		}

		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Doing cache delete under entity's clear_cache method.
		$wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->prefix}gemboards_notified_users SET is_read = 1 WHERE to_user_id = %d AND is_read = 0", get_current_user_id()
			)
		);
		// phpcs:enable

		( new NotifiedUser() )->clear_cache();

		return rest_ensure_response( [
			'success' => true,
		] );
	}

	public function mark_as_read( $request ) {
		$user_id                = get_current_user_id();
		$args                   = [
			'notification_id' => $request->get_param( 'id' ),
			'to_user_id'      => $user_id,
		];
		$cache_group            = 'gemboards_notified_users';
		$cache_key_last_changed = wp_cache_get_last_changed( $cache_group );
		$hash                   = md5( wp_json_encode( $args ) );
		$cache_key              = "get_notified_user_$cache_key_last_changed:$hash";
		$notified_user          = wp_cache_get( $cache_key, $cache_group );
		$notified_id            = $notified_user ? $notified_user->id : null;

		if ( ! $notified_id ) {
			global $wpdb;
			// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
			$result = $wpdb->get_var(
				$wpdb->prepare("SELECT id FROM {$wpdb->prefix}gemboards_notified_users WHERE notification_id = %d AND to_user_id = %d LIMIT 1", $request->get_param( 'id' ), $user_id)
			);
			// phpcs:enable
			$result = absint( $result );
			wp_cache_set( $cache_key, $result, $cache_group );
			$notified_id = $result;
		}

		if ( ! $notified_id ) {
			return new WP_Error( 'rest_invalid_param', __( 'Invalid notification id.', 'gemboards' ), [ 'status' => 400 ] );
		}

		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Doing cache delete under entity's clear_cache method.
		$wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->prefix}gemboards_notified_users SET is_read = 1 WHERE id = %d", $notified_id
			)
		);
		// phpcs:enable

		( new NotifiedUser() )->clear_cache();

		return rest_ensure_response( [
			'is_read' => true,
		] );
	}
}
