<?php
/**
 * Front-end pricing card: shortcode [bw_2checkout_pricing] + the Gutenberg block.
 *
 * Reproduces Copernic's bw-desktop-pricing design (square edges, orange brand, big-number price)
 * but with the price, currency symbol, and buy-link driven by the 2Checkout API, plus an
 * interactive Term toggle and Users stepper. Dynamic (server-rendered) block whose render_callback
 * reuses render() — single source of markup, no JS build step.
 *
 * @package BW_2Checkout_Pricing
 */

defined( 'ABSPATH' ) || exit;

class BW_2Checkout_Pricing_Widget {

	const HANDLE = 'bw-2checkout-pricing';
	const BLOCK  = 'bw-2checkout-pricing/pricing';

	public function __construct() {
		add_action( 'init', array( $this, 'register_shortcode' ) );
		add_action( 'init', array( $this, 'register_block' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) );
	}

	public function register_shortcode() {
		add_shortcode( 'bw_2checkout_pricing', array( $this, 'render' ) );
	}

	public function register_block() {
		if ( ! function_exists( 'register_block_type' ) ) {
			return;
		}

		wp_register_script(
			'bw-2checkout-pricing-editor',
			BW_2CHECKOUT_PRICING_URL . 'assets/js/block-editor.js',
			array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-i18n', 'wp-server-side-render' ),
			BW_2CHECKOUT_PRICING_VERSION,
			true
		);
		wp_localize_script(
			'bw-2checkout-pricing-editor',
			'bw2cpBlock',
			array( 'products' => bw_2checkout_pricing_get_products() )
		);
		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( 'bw-2checkout-pricing-editor', 'bw-2checkout-pricing', BW_2CHECKOUT_PRICING_DIR . 'languages' );
		}

		register_block_type(
			self::BLOCK,
			array(
				'api_version'     => 3,
				'editor_script'   => 'bw-2checkout-pricing-editor',
				'attributes'      => array(
					'product'     => array( 'type' => 'string', 'default' => '' ),
					'locks'       => array( 'type' => 'object', 'default' => array() ),
					'title'       => array( 'type' => 'string', 'default' => '' ),
					'accent'      => array( 'type' => 'string', 'default' => '#f36923' ),
					'buttonLabel' => array( 'type' => 'string', 'default' => '' ),
					'tpl'         => array( 'type' => 'string', 'default' => '' ),
					'perMonth'    => array( 'type' => 'string', 'default' => '' ),
					'annualText'  => array( 'type' => 'string', 'default' => '' ),
					'ribbon'      => array( 'type' => 'boolean', 'default' => false ),
					'ribbonTitle' => array( 'type' => 'string', 'default' => '' ),
					'icons'       => array( 'type' => 'array', 'default' => array() ),
					'hasFooter'   => array( 'type' => 'boolean', 'default' => false ),
					'footerTitle' => array( 'type' => 'string', 'default' => '' ),
					'footerLines' => array( 'type' => 'array', 'default' => array() ),
					'footerImage' => array( 'type' => 'string', 'default' => '' ),
					'hasGmail'    => array( 'type' => 'boolean', 'default' => false ),
					'gmailImage'  => array( 'type' => 'string', 'default' => '' ),
				),
				'render_callback' => array( $this, 'render_block' ),
			)
		);
	}

	/**
	 * Map block attributes to shortcode-style args and render.
	 *
	 * @param array  $a       Block attributes.
	 * @param string $content Inner content (unused).
	 * @return string
	 */
	public function render_block( $a, $content = '' ) {
		$product = ! empty( $a['product'] ) ? $a['product'] : '';
		if ( '' === $product ) {
			$keys    = array_keys( bw_2checkout_pricing_get_products() );
			$product = $keys ? $keys[0] : 'cds';
		}

		$args = array(
			'product'      => $product,
			'title'        => isset( $a['title'] ) ? $a['title'] : '',
			'accent'       => isset( $a['accent'] ) ? $a['accent'] : '#f36923',
			'button_label' => isset( $a['buttonLabel'] ) ? $a['buttonLabel'] : '',
			'tpl'          => isset( $a['tpl'] ) ? $a['tpl'] : '',
			'per_month'    => isset( $a['perMonth'] ) ? $a['perMonth'] : '',
			'annual_text'  => isset( $a['annualText'] ) ? $a['annualText'] : '',
			'ribbon'       => ! empty( $a['ribbon'] ) ? '1' : '0',
			'ribbon_title' => isset( $a['ribbonTitle'] ) ? $a['ribbonTitle'] : '',
			'icons'        => ! empty( $a['icons'] ) ? implode( '|', array_map( array( $this, 'img_url' ), (array) $a['icons'] ) ) : '',
			'footer'       => ! empty( $a['hasFooter'] ) ? '1' : '0',
			'footer_title' => isset( $a['footerTitle'] ) ? $a['footerTitle'] : '',
			'footer_lines' => ! empty( $a['footerLines'] ) ? implode( '|', (array) $a['footerLines'] ) : '',
			'footer_img'   => isset( $a['footerImage'] ) ? $this->img_url( $a['footerImage'] ) : '',
			'gmail'        => ! empty( $a['hasGmail'] ) ? '1' : '0',
			'gmail_img'    => isset( $a['gmailImage'] ) ? $this->img_url( $a['gmailImage'] ) : '',
		);
		if ( ! empty( $a['locks'] ) ) {
			foreach ( (array) $a['locks'] as $key => $val ) {
				if ( '' !== $val && null !== $val ) {
					$args[ 'lock_' . sanitize_key( $key ) ] = sanitize_text_field( $val );
				}
			}
		}
		return $this->render( $args );
	}

	public function register_assets() {
		wp_register_style( self::HANDLE, BW_2CHECKOUT_PRICING_URL . 'assets/css/widget.css', array(), BW_2CHECKOUT_PRICING_VERSION );
		wp_register_script( self::HANDLE, BW_2CHECKOUT_PRICING_URL . 'assets/js/widget.js', array(), BW_2CHECKOUT_PRICING_VERSION, true );
		wp_localize_script(
			self::HANDLE,
			'bw2cpData',
			array(
				'rest'    => esc_url_raw( rest_url( BW_2Checkout_Pricing_REST::NAMESPACE . '/price' ) ),
				'symbols' => bw_2checkout_pricing_currency_symbols(),
				'i18n'    => array(
					'billedAnnually' => __( 'billed annually', 'bw-2checkout-pricing' ),
					/* translators: %s is the number of years. */
					'billedEvery'    => __( 'billed every %s years', 'bw-2checkout-pricing' ),
				),
			)
		);
	}

	/**
	 * Big-number per-month price markup (symbol / integer / fractional+per).
	 *
	 * @param array  $pr        Price array.
	 * @param string $per_month "/month" label.
	 * @return string
	 */
	protected function price_html( $pr, $per_month ) {
		$months  = max( 1, (int) ( isset( $pr['term_months'] ) ? $pr['term_months'] : 12 ) );
		$parts   = explode( '.', number_format( $pr['amount'] / $months, 2, '.', '' ) );
		$int     = number_format( (float) $parts[0], 0 );
		$frac    = isset( $parts[1] ) ? $parts[1] : '00';
		$symbol  = isset( $pr['symbol'] ) ? $pr['symbol'] : bw_2checkout_pricing_currency_symbol( $pr['currency'] );
		$side    = ( isset( $pr['symbol_side'] ) && 'right' === $pr['symbol_side'] ) ? 'right' : 'left';

		$body = '<span class="bw2cp-int">' . esc_html( $int ) . '</span>'
			. '<span class="bw2cp-frac-month">'
			. '<span class="bw2cp-frac">' . esc_html( $frac ) . '</span>'
			. '<span class="bw2cp-per">' . esc_html( '' !== $per_month ? $per_month : __( '/month', 'bw-2checkout-pricing' ) ) . '</span>'
			. '</span>';

		if ( 'right' === $side ) {
			return $body . '<span class="bw2cp-sign bw2cp-sign-after">' . esc_html( $symbol ) . '</span>';
		}
		return '<span class="bw2cp-sign bw2cp-sign-before">' . esc_html( $symbol ) . '</span>' . $body;
	}

	/**
	 * Rough starting font-size (px) for the price so first paint is close before JS fits it exactly.
	 * Weighs the integer length + symbol length against the card's price-area width.
	 *
	 * @param array $pr Price array.
	 * @return int
	 */
	protected function base_price_size( $pr ) {
		$months = max( 1, (int) ( isset( $pr['term_months'] ) ? $pr['term_months'] : 12 ) );
		$parts  = explode( '.', number_format( $pr['amount'] / $months, 2, '.', '' ) );
		$int    = number_format( (float) $parts[0], 0 );
		$sym    = isset( $pr['symbol'] ) ? trim( (string) $pr['symbol'] ) : '';
		// em-weight: integer digits + symbol + the fixed fractional/per block.
		$weight = 0.62 * strlen( $int ) + 0.34 * strlen( $sym ) + 1.7;
		$avail  = 292; // px, approx price-area inner width of a 320px card.
		return (int) min( 84, max( 22, floor( $avail / max( 0.1, $weight ) ) ) );
	}

	/**
	 * Extract a URL from a media attribute that may be a {id,url} object or a plain URL string.
	 *
	 * @param mixed $value Attribute value.
	 * @return string
	 */
	protected function img_url( $value ) {
		if ( is_array( $value ) ) {
			return isset( $value['url'] ) ? (string) $value['url'] : '';
		}
		return (string) $value;
	}

	/**
	 * "$X billed annually / every N years" line (amount from API, text overridable).
	 *
	 * @param array  $pr          Price array.
	 * @param string $annual_text Optional override for the suffix.
	 * @return string
	 */
	protected function billed_text( $pr, $annual_text ) {
		if ( '' !== $annual_text ) {
			$suffix = $annual_text;
		} else {
			$months = max( 1, (int) ( isset( $pr['term_months'] ) ? $pr['term_months'] : 12 ) );
			$suffix = ( 12 !== $months )
				/* translators: %s is the number of years. */
				? sprintf( __( 'billed every %s years', 'bw-2checkout-pricing' ), $months / 12 )
				: __( 'billed annually', 'bw-2checkout-pricing' );
		}
		return $pr['formatted'] . ' ' . $suffix;
	}

	/**
	 * @param array  $atts    Attributes.
	 * @param string $content Inner content.
	 * @return string
	 */
	public function render( $atts, $content = '' ) {
		$raw  = is_array( $atts ) ? $atts : array();
		$atts = shortcode_atts(
			array(
				'product'      => 'cds',
				'title'        => '',
				'accent'       => '#f36923',
				'button_label' => '',
				'tpl'          => '',
				'per_month'    => '',
				'annual_text'  => '',
				'ribbon'       => '0',
				'ribbon_title' => '',
				'icons'        => '',
				'footer'       => '0',
				'footer_title' => '',
				'footer_lines' => '',
				'footer_img'   => '',
				'gmail'        => '0',
				'gmail_img'    => '',
			),
			$raw,
			'bw_2checkout_pricing'
		);

		$products = bw_2checkout_pricing_get_products();
		$pid      = sanitize_key( $atts['product'] );
		if ( ! isset( $products[ $pid ] ) ) {
			return '<div class="bw2cp-widget bw2cp-error">' . esc_html__( 'Unknown product for pricing widget.', 'bw-2checkout-pricing' ) . '</div>';
		}

		$locks = array();
		foreach ( $raw as $k => $v ) {
			if ( 0 === strpos( (string) $k, 'lock_' ) ) {
				$locks[ substr( (string) $k, 5 ) ] = sanitize_text_field( (string) $v );
			}
		}

		wp_enqueue_style( self::HANDLE );
		wp_enqueue_script( self::HANDLE );

		$product      = $products[ $pid ];
		$currencies   = array_filter( array_map( 'trim', explode( ',', (string) bw_2checkout_pricing_get_setting( 'currencies', 'USD' ) ) ) );
		$default_cur  = (string) bw_2checkout_pricing_get_setting( 'default_currency', 'USD' );
		$accent       = sanitize_hex_color( (string) $atts['accent'] ) ? $atts['accent'] : '#f36923';
		$title        = (string) $atts['title'];
		$button_label = '' !== $atts['button_label'] ? $atts['button_label'] : __( 'Buy Now', 'bw-2checkout-pricing' );
		$tpl          = (string) $atts['tpl'];
		$per_month    = (string) $atts['per_month'];
		$annual_text  = (string) $atts['annual_text'];
		$icons        = array_filter( array_map( 'trim', explode( '|', (string) $atts['icons'] ) ) );
		$footer_lines = array_filter( array_map( 'trim', explode( '|', (string) $atts['footer_lines'] ) ) );

		// Default selection + server-rendered price for instant paint.
		$default_options = array();
		foreach ( (array) $product['selectors'] as $sel ) {
			$g = isset( $sel['group'] ) ? (string) $sel['group'] : '';
			if ( '' === $g ) {
				continue;
			}
			$k = isset( $sel['key'] ) ? (string) $sel['key'] : $g;
			if ( isset( $locks[ $k ] ) ) {
				$default_options[ $g ] = $locks[ $k ];
			} elseif ( 'number' === ( isset( $sel['type'] ) ? $sel['type'] : 'select' ) ) {
				$default_options[ $g ] = isset( $sel['default'] ) ? (int) $sel['default'] : 1;
			} else {
				$default_options[ $g ] = isset( $sel['values'][0]['code'] ) ? $sel['values'][0]['code'] : '';
			}
		}
		$prefill = null;
		$pricing = new BW_2Checkout_Pricing_Pricing();
		$pr      = $pricing->get_price( $pid, $default_options, $default_cur );
		if ( ! is_wp_error( $pr ) ) {
			$prefill = array(
				'price'  => $this->price_html( $pr, $per_month ),
				'billed' => $this->billed_text( $pr, $annual_text ),
				'buy'    => $pricing->build_buy_link( $pid, $default_options, $pr['currency'], $tpl ),
				'mock'   => ( isset( $pr['source'] ) && 'mock' === $pr['source'] ),
				'size'   => $this->base_price_size( $pr ),
			);
		}
		$buy = $prefill ? $prefill['buy'] : '#';

		ob_start();
		?>
		<div class="bw2cp-widget bw2cp-card" data-product="<?php echo esc_attr( $pid ); ?>" data-tpl="<?php echo esc_attr( $tpl ); ?>" data-permonth="<?php echo esc_attr( $per_month ); ?>" data-annual="<?php echo esc_attr( $annual_text ); ?>"<?php echo $prefill ? ' data-prefilled="1"' : ''; ?> style="--bw2cp-accent: <?php echo esc_attr( $accent ); ?>;">

			<div class="bw2cp-header">
				<?php if ( '1' === $atts['ribbon'] && '' !== $atts['ribbon_title'] ) : ?>
					<span class="bw2cp-ribbon"><?php echo esc_html( $atts['ribbon_title'] ); ?></span>
				<?php endif; ?>
				<a class="bw2cp-title-link" href="<?php echo esc_url( $buy ); ?>" target="_blank" rel="nofollow"><?php echo esc_html( '' !== $title ? $title : $product['label'] ); ?></a>

				<div class="bw2cp-controls-row">
					<?php
					foreach ( (array) $product['selectors'] as $sel ) :
						$group = isset( $sel['group'] ) ? (string) $sel['group'] : '';
						if ( '' === $group ) {
							continue;
						}
						$type      = isset( $sel['type'] ) ? (string) $sel['type'] : 'select';
						$key       = isset( $sel['key'] ) ? (string) $sel['key'] : $group;
						$sel_label = bw_2checkout_pricing_tr( isset( $sel['label'] ) ? $sel['label'] : $group, 'selector_' . $key . '_label' );
						$locked    = isset( $locks[ $key ] ) ? $locks[ $key ] : null;
						$values    = (array) ( isset( $sel['values'] ) ? $sel['values'] : array() );

						if ( null !== $locked ) :
							?>
							<input type="hidden" data-group="<?php echo esc_attr( $group ); ?>" value="<?php echo esc_attr( $locked ); ?>" />
							<?php
						elseif ( 'number' === $type ) :
							?>
							<span class="bw2cp-users">
								<span class="bw2cp-users-label"><?php echo esc_html( $sel_label ); ?></span>
								<span class="bw2cp-num">
									<input type="number" class="bw2cp-users-input" data-group="<?php echo esc_attr( $group ); ?>" min="<?php echo esc_attr( isset( $sel['min'] ) ? (int) $sel['min'] : 1 ); ?>" value="<?php echo esc_attr( isset( $sel['default'] ) ? (int) $sel['default'] : 1 ); ?>" />
									<span class="bw2cp-num-btns">
										<button type="button" class="bw2cp-step" data-dir="up" aria-label="<?php esc_attr_e( 'Increase', 'bw-2checkout-pricing' ); ?>">&#9650;</button>
										<button type="button" class="bw2cp-step" data-dir="down" aria-label="<?php esc_attr_e( 'Decrease', 'bw-2checkout-pricing' ); ?>">&#9660;</button>
									</span>
								</span>
							</span>
							<?php
						else :
							$first       = isset( $values[0] ) ? $values[0] : array();
							$first_code  = isset( $first['code'] ) ? $first['code'] : '';
							$first_label = bw_2checkout_pricing_tr( isset( $first['label'] ) ? $first['label'] : $first_code, 'option_' . $group . '_' . $first_code );
							?>
							<span class="bw2cp-dropdown" data-group="<?php echo esc_attr( $group ); ?>">
								<input type="hidden" data-group="<?php echo esc_attr( $group ); ?>" value="<?php echo esc_attr( $first_code ); ?>" />
								<button type="button" class="bw2cp-dd-toggle" aria-haspopup="listbox" aria-expanded="false" aria-label="<?php echo esc_attr( $sel_label ); ?>">
									<span class="bw2cp-dd-label"><?php echo esc_html( $first_label ); ?></span>
									<span class="bw2cp-dd-caret" aria-hidden="true">&#9662;</span>
								</button>
								<ul class="bw2cp-dd-menu" role="listbox" hidden>
									<?php
									$i = 0;
									foreach ( $values as $opt ) :
										$code = isset( $opt['code'] ) ? $opt['code'] : '';
										?>
										<li class="bw2cp-dd-option<?php echo ( 0 === $i ) ? ' is-active' : ''; ?>" role="option" data-value="<?php echo esc_attr( $code ); ?>">
											<?php echo esc_html( bw_2checkout_pricing_tr( isset( $opt['label'] ) ? $opt['label'] : $code, 'option_' . $group . '_' . $code ) ); ?>
										</li>
										<?php
										++$i;
									endforeach;
									?>
								</ul>
							</span>
							<?php
						endif;
					endforeach;
					?>
				</div>
			</div>

			<div class="bw2cp-price">
				<div class="bw2cp-per-month"<?php echo $prefill ? ' style="font-size:' . (int) $prefill['size'] . 'px"' : ''; ?>><?php echo $prefill ? $prefill['price'] : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built + escaped in price_html(). ?></div>
				<p class="bw2cp-per-year"><?php echo $prefill ? esc_html( $prefill['billed'] ) : ''; ?></p>

				<div class="bw2cp-currency-row">
					<select class="bw2cp-currency" aria-label="<?php esc_attr_e( 'Currency', 'bw-2checkout-pricing' ); ?>">
						<?php foreach ( $currencies as $cur ) : ?>
							<option value="<?php echo esc_attr( $cur ); ?>" <?php selected( $cur, $default_cur ); ?>><?php echo esc_html( $cur ); ?></option>
						<?php endforeach; ?>
					</select>
					<span class="bw2cp-currency-note"><?php esc_html_e( '(selectable for testing, will autodetect)', 'bw-2checkout-pricing' ); ?></span>
				</div>
			</div>

			<div class="bw2cp-extensions">
				<?php if ( ! empty( $icons ) ) : ?>
					<div class="bw2cp-icon-list">
						<?php foreach ( $icons as $icon ) : ?>
							<img src="<?php echo esc_url( $icon ); ?>" alt="" />
						<?php endforeach; ?>
					</div>
				<?php endif; ?>

				<?php if ( '1' === $atts['gmail'] && '' !== $atts['gmail_img'] ) : ?>
					<div class="bw2cp-gmail"><img src="<?php echo esc_url( $atts['gmail_img'] ); ?>" alt="" /></div>
				<?php endif; ?>

				<?php if ( '1' === $atts['footer'] ) : ?>
					<div class="bw2cp-footer">
						<div class="bw2cp-footer-info">
							<?php if ( '' !== $atts['footer_title'] ) : ?>
								<div class="bw2cp-footer-title"><?php echo esc_html( $atts['footer_title'] ); ?></div>
							<?php endif; ?>
							<?php foreach ( $footer_lines as $line ) : ?>
								<p><?php echo esc_html( $line ); ?></p>
							<?php endforeach; ?>
						</div>
						<?php if ( '' !== $atts['footer_img'] ) : ?>
							<img src="<?php echo esc_url( $atts['footer_img'] ); ?>" alt="" />
						<?php endif; ?>
					</div>
				<?php endif; ?>
			</div>

			<a class="bw2cp-buy" href="<?php echo esc_url( $buy ); ?>" target="_blank" rel="nofollow"><?php echo esc_html( $button_label ); ?></a>

			<p class="bw2cp-mock-note" style="<?php echo ( $prefill && $prefill['mock'] ) ? '' : 'display:none;'; ?>"><?php esc_html_e( 'Illustrative pricing — live 2Checkout price unavailable right now.', 'bw-2checkout-pricing' ); ?></p>
			<p class="bw2cp-tax-note"><?php esc_html_e( 'Prices shown are net; applicable tax is added at checkout.', 'bw-2checkout-pricing' ); ?></p>
		</div>
		<?php
		return (string) ob_get_clean();
	}
}
