<?php

namespace Cookiez\Classes\Utils;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

/**
 * Class Notice_Base
 */
class Notice_Base {
	/**
	 * The action prefix for the notice
	 *
	 * @var string
	 */
	const ACTION_PREFIX = 'cookiez_admin_notice';

	/**
	 * The option name / meta key for dismissed notices
	 *
	 * @var string
	 */
	const DISMISSED_NOTICES = 'cookiez_dismissed_notices';

	/**
	 * @var bool $conditions
	 */
	public bool $conditions = true;

	/**
	 * Whether the notice is dismissible
	 *
	 * @var bool
	 */
	public bool $is_dismissible = false;

	/**
	 * Whether the notice is dismissible per user or globally
	 *
	 * @var bool
	 */
	public bool $per_user = true;

	/**
	 * The notice ID
	 *
	 * @var string
	 */
	public string $id = '';

	/**
	 * The notice content
	 *
	 * @var string
	 */
	public string $content;

	/**
	 * should be one of 'info', 'warning', 'error', 'success', 'error-elementor'
	 * @var string
	 */
	public string $type;

	/**
	 * @var mixed|string
	 */
	public $capability;

	/**
	 * Get the notice ID
	 *
	 * @return string
	 */
	public function get_id(): string {
		return $this->id;
	}

	/**
	 * Get the action name for the notice
	 *
	 * @return string
	 */
	public function get_action_name(): string {
		return self::ACTION_PREFIX . '_' . $this->get_id();
	}

	public function show(): bool {
		if ( ! $this->conditions ) {
			return false;
		}
		if ( $this->is_dismissible && $this->is_dismissed() ) {
			return false;
		}
		if ( $this->capability && ! current_user_can( $this->capability ) ) {
			return false;
		}
		return true;
	}

	public function is_dismissed(): bool {
		$dismissed = $this->per_user ?
			get_user_meta( get_current_user_id(), self::DISMISSED_NOTICES, true ) :
			get_option( self::DISMISSED_NOTICES, [] );

		return in_array( $this->get_id(), (array) $dismissed );
	}

	public function dismiss(): void {
		$dismissed = get_option( self::DISMISSED_NOTICES, [] );
		$dismissed[] = $this->get_id();
		update_option( self::DISMISSED_NOTICES, $dismissed, false );
	}

	public function undismiss(): void {
		$dismissed = get_option( self::DISMISSED_NOTICES, [] );

		if ( ! in_array( $this->get_id(), $dismissed ) ) {
			return;
		}

		$dismissed = array_diff( $dismissed, [ $this->get_id() ] );
		update_option( self::DISMISSED_NOTICES, $dismissed, false );
	}

	public function dismiss_per_user(): void {
		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			wp_send_json_error( [ 'message' => 'Invalid user' ] );
		}
		$dismissed = get_user_meta( $user_id, self::DISMISSED_NOTICES, true );
		if ( ! $dismissed ) {
			$dismissed = [];
		}
		$dismissed[] = $this->get_id();
		update_user_meta( $user_id, self::DISMISSED_NOTICES, $dismissed );
	}

	public function handle_dismiss() {
		if ( ! $this->is_dismissible ) {
			return;
		}
		if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), $this->get_action_name() ) ) {
			wp_send_json_error( [ 'message' => 'Invalid nonce' ] );
		}

		if ( $this->per_user ) {
			$this->dismiss_per_user();
		} else {
			$this->dismiss();
		}

		wp_send_json_success( [] );
	}

	public function render() {
		printf(
			'<div role="region" aria-label="%1$s" class="notice_wrapper notice %2$s notice-%3$s %3$s %4$s" data-notice-id="%4$s" data-notice-action="%5$s" data-notice-nonce="%6$s">%7$s</div>',
			esc_attr__( 'Notice', 'cookiez' ),
			$this->is_dismissible ? 'cookiez-dismiss is-dismissible' : '',
			esc_attr( $this->type ),
			esc_attr( $this->get_id() ),
			esc_attr( $this->get_action_name() ),
			esc_attr( wp_create_nonce( $this->get_action_name() ) ),
			wp_kses_post( $this->content() )
		);
	}

	public function print_js() {
		$action = 'admin_notices_print_js';

		if ( did_action( $action ) ) {
			return;
		}

		do_action( $action );

		echo ( '
			<script>
				jQuery( document ).ready( function() {
					jQuery( ".cookiez-dismiss" ).on( "click", function( e ) {
						if ( ! e.target.classList.contains( "notice-dismiss" ) && ! e.target.classList.contains( "cookiez-dismiss-button" ) ) {
							return;
						}
						const $this = jQuery( this );
						const data = {
							action: "cookiez_admin_notice_dismiss",
							nonce: $this.data( "notice-nonce" ),
							notice_id: $this.data( "notice-id" ),
						};
						jQuery.post( ajaxurl, data, function( response ) {
							if ( response.success ) {
								$this.slideUp();
							}
						} );
					} );
				} );
			</script>
		' );
	}

	public function maybe_show_notice() {
		if ( ! $this->show() ) {
			return;
		}
		if ( $this->is_dismissible ) {
			add_action( 'admin_footer', [ $this, 'print_js' ] );
		}

		$this->render();
	}

	public function content(): string {
		return $this->content;
	}

	/**
	 * @throws \Exception
	 */
	public function __construct() {
		if ( ! $this->content() ) {
			throw new \Exception( 'Notice content is required' );
		}

		if ( ! in_array( $this->type, [ 'info', 'warning', 'error', 'success', 'error-elementor' ] ) ) {
			throw new \Exception( 'Invalid notice type' );
		}
	}
}
