<?php

namespace Cart\notify\Settings;

defined( 'ABSPATH' ) || exit;

/**
 * Cart Notify settings repository.
 */
class Repository {
	/**
	 * Option key in wp_options.
	 */
	const OPTION_KEY = 'CartCNS';

	/**
	 * Fallback defaults.
	 *
	 * @var array
	 */
	private $defaults = array(
		'cns-notify-opt'        => 'notify',
		'cns-enable-notify'     => '1',
		'cns-success-message'   => 'The product has been successfully added to the cart.',
		'cns-prestyle'          => 'cns-prestyle-1',
		'cns-notify-position'   => 'right-bottom',
		'cns-notify-duration'   => 3000,
		'cns-show-image'        => '1',
		'cns-mobile-visibility' => 'show',
		'cns-cta-view-cart'     => '1',
		'cns-cta-checkout'      => '1',
		'cns-cta-continue'      => '0',
		'cns-bg-color'          => '#e3ffed',
		'cns-text-color'        => '#00080c',
		'cns-link-color'        => '#104222',
		'cns-border-color'      => '#d7e8de',
		'wi-custom-css'         => '',
	);

	/**
	 * Allowed position keys.
	 *
	 * @var array
	 */
	private $allowed_positions = array( 'right-top', 'right-bottom', 'left-top', 'left-bottom' );

	/**
	 * Get one option by key.
	 *
	 * @param string $key Option key.
	 * @param mixed  $default Optional fallback value.
	 * @return mixed
	 */
	public function get( $key = '', $default = null ) {
		if ( '' === $key ) {
			return $this->all();
		}

		$options = $this->all();
		$fallback = null !== $default ? $default : ( isset( $this->defaults[ $key ] ) ? $this->defaults[ $key ] : null );

		return isset( $options[ $key ] ) ? $options[ $key ] : $fallback;
	}

	/**
	 * Get merged settings array.
	 *
	 * @return array
	 */
	public function all() {
		$options = get_option( self::OPTION_KEY, array() );
		$options = is_array( $options ) ? $options : array();

		return array_merge( $this->defaults, $options );
	}

	/**
	 * Get validated notification position.
	 *
	 * @return string
	 */
	public function get_notification_position() {
		return self::sanitize_position( $this->get( 'cns-notify-position', 'right-bottom' ) );
	}

	/**
	 * Check whether notification is enabled.
	 *
	 * @return bool
	 */
	public function is_notification_enabled() {
		$notify_mode = self::sanitize_notification_option( $this->get( 'cns-notify-opt', 'notify' ) );
		if ( 'notify' !== $notify_mode ) {
			return false;
		}

		return self::is_truthy( $this->get( 'cns-enable-notify', '1' ) );
	}

	/**
	 * Get frontend success message.
	 *
	 * @return string
	 */
	public function get_success_message() {
		$message = $this->get( 'cns-success-message', $this->defaults['cns-success-message'] );
		$message = self::sanitize_text( $message );

		if ( '' === $message ) {
			$message = $this->defaults['cns-success-message'];
		}

		return $message;
	}

	/**
	 * Get notification autohide duration in milliseconds.
	 *
	 * @return int
	 */
	public function get_notification_duration() {
		return self::sanitize_duration( $this->get( 'cns-notify-duration', $this->defaults['cns-notify-duration'] ) );
	}

	/**
	 * Check whether image display is enabled.
	 *
	 * @return bool
	 */
	public function should_show_image() {
		return self::is_truthy( $this->get( 'cns-show-image', '1' ) );
	}

	/**
	 * Check whether notifications should render on mobile.
	 *
	 * @return bool
	 */
	public function show_on_mobile() {
		return 'hide' !== self::sanitize_mobile_visibility( $this->get( 'cns-mobile-visibility', 'show' ) );
	}

	/**
	 * Get CTA visibility configuration.
	 *
	 * @return array
	 */
	public function get_cta_flags() {
		return array(
			'view_cart' => self::is_truthy( $this->get( 'cns-cta-view-cart', '1' ) ),
			'checkout'  => self::is_truthy( $this->get( 'cns-cta-checkout', '1' ) ),
			'continue'  => self::is_truthy( $this->get( 'cns-cta-continue', '0' ) ),
		);
	}

	/**
	 * Get style preset key.
	 *
	 * @return string
	 */
	public function get_style_preset() {
		return self::sanitize_style_preset( $this->get( 'cns-prestyle', $this->defaults['cns-prestyle'] ) );
	}

	/**
	 * Get style preset class.
	 *
	 * @return string
	 */
	public function get_style_class() {
		return 'cns-style-' . sanitize_html_class( $this->get_style_preset() );
	}

	/**
	 * Get CSS variable values for frontend notification.
	 *
	 * @return array
	 */
	public function get_style_tokens() {
		$bg_color     = self::sanitize_hex_color( $this->get( 'cns-bg-color', $this->defaults['cns-bg-color'] ) );
		$text_color   = self::sanitize_hex_color( $this->get( 'cns-text-color', $this->defaults['cns-text-color'] ) );
		$link_color   = self::sanitize_hex_color( $this->get( 'cns-link-color', $this->defaults['cns-link-color'] ) );
		$border_color = self::sanitize_hex_color( $this->get( 'cns-border-color', $this->defaults['cns-border-color'] ) );

		return array(
			'--CNS-primary-bg'          => $bg_color ? $bg_color : $this->defaults['cns-bg-color'],
			'--CNS-primary-text'        => $text_color ? $text_color : $this->defaults['cns-text-color'],
			'--CNS-primary-anchor-color' => $link_color ? $link_color : $this->defaults['cns-link-color'],
			'--CNS-border-color'        => $border_color ? $border_color : $this->defaults['cns-border-color'],
		);
	}

	/**
	 * Get custom CSS from settings.
	 *
	 * @return string
	 */
	public function get_custom_css() {
		return self::sanitize_custom_css( $this->get( 'wi-custom-css', '' ) );
	}

	/**
	 * Sanitize switcher values.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_switch( $value ) {
		return self::is_truthy( $value ) ? '1' : '0';
	}

	/**
	 * Sanitize notification option.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_notification_option( $value ) {
		$value = is_string( $value ) ? $value : 'notify';

		return in_array( $value, array( 'notify' ), true ) ? $value : 'notify';
	}

	/**
	 * Sanitize notification position.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_position( $value ) {
		$allowed  = array( 'right-top', 'right-bottom', 'left-top', 'left-bottom' );
		$position = is_string( $value ) ? $value : 'right-bottom';

		return in_array( $position, $allowed, true ) ? $position : 'right-bottom';
	}

	/**
	 * Sanitize free-text values.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_text( $value ) {
		return sanitize_text_field( (string) $value );
	}

	/**
	 * Sanitize duration with safe limits.
	 *
	 * @param mixed $value Incoming value.
	 * @return int
	 */
	public static function sanitize_duration( $value ) {
		$duration = absint( $value );
		if ( $duration < 1000 ) {
			$duration = 1000;
		}
		if ( $duration > 20000 ) {
			$duration = 20000;
		}

		return $duration;
	}

	/**
	 * Sanitize mobile visibility setting.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_mobile_visibility( $value ) {
		$mode = is_string( $value ) ? $value : 'show';

		return in_array( $mode, array( 'show', 'hide' ), true ) ? $mode : 'show';
	}

	/**
	 * Sanitize style preset key.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_style_preset( $value ) {
		$preset = is_string( $value ) ? $value : 'cns-prestyle-1';

		return in_array( $preset, array( 'cns-prestyle-1' ), true ) ? $preset : 'cns-prestyle-1';
	}

	/**
	 * Sanitize hex color.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_hex_color( $value ) {
		$sanitized = sanitize_hex_color( (string) $value );

		return is_string( $sanitized ) ? $sanitized : '';
	}

	/**
	 * Sanitize custom CSS setting.
	 *
	 * @param mixed $value Incoming value.
	 * @return string
	 */
	public static function sanitize_custom_css( $value ) {
		$value = is_string( $value ) ? $value : '';

		return trim( wp_strip_all_tags( $value, false ) );
	}

	/**
	 * Normalize "truthy" setting values.
	 *
	 * @param mixed $value Incoming value.
	 * @return bool
	 */
	private static function is_truthy( $value ) {
		if ( is_bool( $value ) ) {
			return $value;
		}

		return in_array( $value, array( 1, '1', 'true', 'yes', 'on' ), true );
	}
}
