<?php
/**
 * Notification service for managing admin and in-app notifications.
 *
 * @package RewardsWP
 */

namespace Awesomemotive\Rewardswp\Services;

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

use Awesomemotive\Rewardswp\Abstracts\AbstractModelService;
use Awesomemotive\Rewardswp\Database\DatabaseHandler;
use Awesomemotive\Rewardswp\Database\Tables\NotificationsTable;
use Awesomemotive\Rewardswp\Models\Notification;
use DI\Container;
use function Awesomemotive\Rewardswp\Helpers\get_current_time;
use function Awesomemotive\Rewardswp\Helpers\get_rewardswp_plan_tier;

/**
 * Service for managing admin notifications across the application.
 *
 * @since 1.0.0
 */
class NotificationService extends AbstractModelService {

	/**
	 * Constructor.
	 *
	 * @since 1.1.0
	 *
	 * @param DatabaseHandler    $db_handler Database handler instance.
	 * @param NotificationsTable $db_table   Notifications table instance.
	 * @param Container          $container  DI Container instance.
	 */
	public function __construct(
		DatabaseHandler $db_handler,
		NotificationsTable $db_table,
		Container $container
	) {
		parent::__construct( $db_handler, $db_table, $container );
	}

	/**
	 * Get active notifications from database.
	 *
	 * Fetches notifications that are not dismissed and are within their display window.
	 *
	 * @since 1.1.0
	 *
	 * @return Notification[] List of active notification models.
	 */
	private function get_active_notifications(): array {
		$current_license = get_rewardswp_plan_tier();
		$current_time    = \Awesomemotive\Rewardswp\Helpers\get_current_time();
		$table_name      = $this->db_table->get_prefixed_table_name();

		// Build SQL query with date conditions.
		// License filtering will be done in PHP since conditions is a JSON array.
		$sql = "SELECT * FROM {$table_name}
				WHERE dismissed = 0
				AND (start IS NULL OR start <= %s)
				AND (end IS NULL OR end >= %s)
				ORDER BY created_at DESC
				LIMIT 999";

		$results = $this->db_handler->query(
			$sql,
			[ $current_time, $current_time ],
			true,
			'rewardswp_notifications'
		);

		if ( empty( $results ) ) {
			return [];
		}

		// Hydrate results into Notification models and filter by license.
		$notifications = [];
		foreach ( $results as $row ) {
			/**
			 * Notification model instance.
			 *
			 * @var Notification $notification
			 */
			$notification = $this->container->make( Notification::class );
			$notification->hydrate( $row );

			// Filter by license level (conditions array).
			if ( $notification->is_active( $current_license ) ) {
				$notifications[] = $notification;
			}
		}

		return $notifications;
	}

	/**
	 * Get the current state of notifications.
	 *
	 * @since 1.0.0
	 *
	 * @return array {
	 *     @type array $notifications List of notification items.
	 *     @type int   $perPage Number of notifications per page.
	 *     @type int   $widgetPreview Number of notifications to show in widget preview.
	 *     @type array $translations Translated strings for the frontend.
	 * }
	 */
	public function get_notifications_state(): array {
		// Get active notifications from database.
		$active_notifications = $this->get_active_notifications();

		// Get timezone and date format settings.
		$timezone = wp_timezone();
		if ( ! $timezone instanceof \DateTimeZone ) {
			$timezone_string = wp_timezone_string();
			$timezone        = $timezone_string ? new \DateTimeZone( $timezone_string ) : new \DateTimeZone( 'UTC' );
		}

		$date_format = get_option( 'date_format' );
		if ( ! is_string( $date_format ) || '' === $date_format ) {
			$date_format = 'M j, Y';
		}

		// Process notifications for frontend.
		$notifications_for_frontend = [];
		foreach ( $active_notifications as $notification ) {
			$timestamp = ! empty( $notification->created_at ) ? strtotime( $notification->created_at ) : null;

			$frontend_notification = [
				'id'                => (string) $notification->id,
				'title'             => $notification->title,
				'message'           => wpautop( $notification->content ),
				'timestamp'         => $timestamp,
				'date'              => $timestamp ? wp_date( $date_format, $timestamp, $timezone ) : '',
				'notification_type' => $notification->type,
				'learn_more_url'    => '#',
				'dismiss_url'       => '#',
			];

			// Include buttons if present.
			$buttons = $notification->get_buttons_array();
			if ( ! empty( $buttons ) ) {
				$frontend_notification['btns'] = [];
				foreach ( $buttons as $button ) {
					$raw_url  = $button['url'] ?? '#';
					$btn_type = 'primary' === $button['type'] ? 'main' : 'alt';

					$frontend_notification['btns'][ $btn_type ] = [
						'url'      => $this->resolve_url_placeholders( $raw_url ),
						'text'     => $button['text'] ?? '',
						'external' => 0 === strpos( $raw_url, 'http' ),
					];
				}
			}

			$notifications_for_frontend[] = $frontend_notification;
		}

		return [
			'notifications' => $notifications_for_frontend,
			'perPage'       => 5,
			'widgetPreview' => 5,
			'translations'  => [
				'newNotifications'          => __( 'New Notifications', 'rewardswp' ),
				'noNotifications'           => __( 'No new notifications', 'rewardswp' ),
				'dismissAll'                => __( 'Dismiss All', 'rewardswp' ),
				'viewNotifications'         => __( 'View Notifications', 'rewardswp' ),
				/* translators: %d: Number of additional notifications. */
				'moreNotificationsSingular' => __( 'You have %d more notification', 'rewardswp' ),
				/* translators: %d: Number of additional notifications. */
				'moreNotificationsPlural'   => __( 'You have %d more notifications', 'rewardswp' ),
			],
		];
	}

	/**
	 * Replace placeholder tags in notification URLs.
	 *
	 * Supports {admin_url}, {site_url}, and {license_key} placeholders
	 * that resolve to WordPress-generated values at render time.
	 *
	 * @since 1.3.0
	 *
	 * @param string $url The URL potentially containing placeholders.
	 * @return string The URL with placeholders resolved.
	 */
	private function resolve_url_placeholders( string $url ): string {
		$placeholders = [
			'{admin_url}'   => admin_url(),
			'{site_url}'    => site_url( '/' ),
			'{license_key}' => $this->container->get( LicenseManagerService::class )->get_license_key(),
		];

		return str_replace(
			array_keys( $placeholders ),
			array_values( $placeholders ),
			$url
		);
	}

	/**
	 * Dismiss a notification.
	 *
	 * @since 1.0.0
	 *
	 * @param int $notification_id The ID of the notification to dismiss.
	 * @return bool True on success, false on failure.
	 */
	public function dismiss_notification( int $notification_id ): bool {
		if ( empty( $notification_id ) ) {
			return false;
		}

		return (bool) $this->db_handler->update(
			$this->db_table->get_prefixed_table_name(),
			[ 'dismissed' => 1 ],
			[ 'id' => $notification_id ]
		);
	}

	/**
	 * Dismiss all notifications.
	 *
	 * @since 1.0.0
	 *
	 * @return bool True on success, false on failure.
	 */
	public function dismiss_all_notifications(): bool {
		$updated = $this->db_handler->update(
			$this->db_table->get_prefixed_table_name(),
			[
				'dismissed' => 1,
			],
			[
				'dismissed' => 0,
			]
		);

		return false !== $updated;
	}

	/**
	 * Get notifications based on the given parameters.
	 *
	 * @since 1.1.0
	 *
	 * @param array $where    An associative array of conditions to filter notifications.
	 * @param int   $per_page Optional. The number of items per page for pagination. Defaults to 10.
	 * @param int   $page     Optional. The page number for pagination. Defaults to 1.
	 *
	 * @return Notification[] Array of Notification objects.
	 */
	public function get_notifications( array $where = [], int $per_page = 10, int $page = 1 ): array {
		return $this->get_objects( Notification::class, $where, $per_page, $page );
	}

	/**
	 * Count the number of notifications based on the given parameters.
	 *
	 * @since 1.1.0
	 *
	 * @param array $where An associative array of conditions to filter notifications.
	 * @return int The number of notifications found.
	 */
	public function count_notifications( array $where = [] ): int {
		return $this->count_objects( $where );
	}
}
