<?php

declare(strict_types=1);

namespace Australcode\Rewards\Admin;

use Australcode\Rewards\Infrastructure\Earning\MetaEarningOverrideResolver;
use WP_Post;
use WP_Term;

defined( 'ABSPATH' ) || exit;

/**
 * Admin UI for the FREE per-product / per-category earning overrides (Phase 1.b):
 * a "Australcode Rewards rewards" meta box on the product editor and a multiplier + exclude
 * field on product categories. Both write the same meta keys the
 * MetaEarningOverrideResolver reads.
 */
final class ProductEarningAdmin {

	private const NONCE      = 'acrwd_product_earning';
	private const MULTIPLIER = MetaEarningOverrideResolver::MULTIPLIER_META;
	private const EXCLUDED   = MetaEarningOverrideResolver::EXCLUDED_META;

	public function register(): void {
		add_action( 'add_meta_boxes_product', array( $this, 'add_meta_box' ) );
		add_action( 'save_post_product', array( $this, 'save_product' ), 10, 1 );

		add_action( 'product_cat_add_form_fields', array( $this, 'render_category_add_field' ) );
		add_action( 'product_cat_edit_form_fields', array( $this, 'render_category_edit_field' ) );
		add_action( 'created_product_cat', array( $this, 'save_category' ) );
		add_action( 'edited_product_cat', array( $this, 'save_category' ) );
	}

	public function add_meta_box(): void {
		add_meta_box(
			'acrwd-product-earning',
			__( 'Australcode Rewards rewards', 'australcode-points-rewards' ),
			array( $this, 'render_meta_box' ),
			'product',
			'side'
		);
	}

	public function render_meta_box( WP_Post $post ): void {
		$multiplier = (string) get_post_meta( $post->ID, self::MULTIPLIER, true );
		$excluded   = '1' === (string) get_post_meta( $post->ID, self::EXCLUDED, true );
		wp_nonce_field( self::NONCE, self::NONCE );

		echo '<p><label for="acrwd-earn-multiplier"><strong>' . esc_html__( 'Earning multiplier', 'australcode-points-rewards' ) . '</strong></label><br/>';
		echo '<input type="number" step="0.1" min="0" id="acrwd-earn-multiplier" name="' . esc_attr( self::MULTIPLIER ) . '" value="' . esc_attr( $multiplier ) . '" placeholder="1.0" class="widefat" /></p>';
		echo '<p class="description">' . esc_html__( 'Multiplies the points earned for this product. Leave blank for 1×.', 'australcode-points-rewards' ) . '</p>';

		echo '<p><label><input type="checkbox" name="' . esc_attr( self::EXCLUDED ) . '" value="1" ' . checked( $excluded, true, false ) . ' /> '
			. esc_html__( 'Exclude this product from earning', 'australcode-points-rewards' ) . '</label></p>';
	}

	public function save_product( int $post_id ): void {
		if ( ! $this->verified_request() ) {
			return;
		}
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}
		$this->persist( static fn ( string $key, string $value ) => update_post_meta( $post_id, $key, $value ), static fn ( string $key ) => delete_post_meta( $post_id, $key ) );
	}

	public function render_category_add_field(): void {
		wp_nonce_field( self::NONCE, self::NONCE );
		echo '<div class="form-field"><label for="acrwd-cat-multiplier">' . esc_html__( 'Australcode Rewards earning multiplier', 'australcode-points-rewards' ) . '</label>';
		echo '<input type="number" step="0.1" min="0" id="acrwd-cat-multiplier" name="' . esc_attr( self::MULTIPLIER ) . '" value="" placeholder="1.0" />';
		echo '<p>' . esc_html__( 'Multiplies points for products in this category (unless the product sets its own).', 'australcode-points-rewards' ) . '</p></div>';
		echo '<div class="form-field"><label><input type="checkbox" name="' . esc_attr( self::EXCLUDED ) . '" value="1" /> '
			. esc_html__( 'Exclude this category from earning', 'australcode-points-rewards' ) . '</label></div>';
	}

	public function render_category_edit_field( WP_Term $term ): void {
		$multiplier = (string) get_term_meta( $term->term_id, self::MULTIPLIER, true );
		$excluded   = '1' === (string) get_term_meta( $term->term_id, self::EXCLUDED, true );
		wp_nonce_field( self::NONCE, self::NONCE );

		echo '<tr class="form-field"><th scope="row"><label for="acrwd-cat-multiplier">' . esc_html__( 'Australcode Rewards earning multiplier', 'australcode-points-rewards' ) . '</label></th><td>';
		echo '<input type="number" step="0.1" min="0" id="acrwd-cat-multiplier" name="' . esc_attr( self::MULTIPLIER ) . '" value="' . esc_attr( $multiplier ) . '" placeholder="1.0" />';
		echo '<p class="description">' . esc_html__( 'Multiplies points for products in this category (unless the product sets its own).', 'australcode-points-rewards' ) . '</p></td></tr>';

		echo '<tr class="form-field"><th scope="row">' . esc_html__( 'Exclude from earning', 'australcode-points-rewards' ) . '</th><td>';
		echo '<label><input type="checkbox" name="' . esc_attr( self::EXCLUDED ) . '" value="1" ' . checked( $excluded, true, false ) . ' /> '
			. esc_html__( 'Products in this category earn no points', 'australcode-points-rewards' ) . '</label></td></tr>';
	}

	public function save_category( int $term_id ): void {
		if ( ! $this->verified_request() ) {
			return;
		}
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}
		$this->persist( static fn ( string $key, string $value ) => update_term_meta( $term_id, $key, $value ), static fn ( string $key ) => delete_term_meta( $term_id, $key ) );
	}

	private function verified_request(): bool {
		return isset( $_POST[ self::NONCE ] )
			&& false !== wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE ] ) ), self::NONCE );
	}

	/**
	 * Writes the multiplier (when > 0) and exclusion flag from the verified
	 * request via the supplied update/delete callbacks (post meta or term meta).
	 *
	 * @param callable(string,string):mixed $update
	 * @param callable(string):mixed        $delete
	 */
	private function persist( callable $update, callable $delete ): void {
		// Nonce verified by the caller via verified_request().
		$multiplier = isset( $_POST[ self::MULTIPLIER ] ) ? (float) $_POST[ self::MULTIPLIER ] : 0.0; // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- nonce checked in verified_request(); cast to float sanitizes.
		if ( $multiplier > 0 ) {
			$update( self::MULTIPLIER, (string) $multiplier );
		} else {
			$delete( self::MULTIPLIER );
		}

		if ( isset( $_POST[ self::EXCLUDED ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce checked in verified_request().
			$update( self::EXCLUDED, '1' );
		} else {
			$delete( self::EXCLUDED );
		}
	}
}
