<?php

namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;

use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;

/**
 * Products Task
 */
class Products extends Task {
	const HAS_PRODUCT_TRANSIENT = 'woocommerce_product_task_has_product_transient';

	/**
	 * Whether a deferred revert check has already been scheduled for this request.
	 *
	 * @var bool
	 */
	private static $revert_scheduled = false;

	/**
	 * Constructor
	 *
	 * @param TaskList $task_list Parent task list.
	 */
	public function __construct( $task_list ) {
		parent::__construct( $task_list );
		add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_import_return_notice_script' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_load_sample_return_notice_script' ) );

		add_action( 'woocommerce_update_product', array( $this, 'maybe_set_has_product_transient' ), 10, 2 );
		add_action( 'woocommerce_new_product', array( $this, 'maybe_set_has_product_transient' ), 10, 2 );
		add_action( 'untrashed_post', array( $this, 'maybe_set_has_product_transient_on_untrashed_post' ) );
		add_action( 'current_screen', array( $this, 'maybe_redirect_to_add_product_tasklist' ), 30, 0 );

		add_action( 'trashed_post', array( $this, 'on_product_trashed' ) );
		add_action( 'deleted_post_product', array( $this, 'on_product_deleted' ) );
	}

	/**
	 * ID.
	 *
	 * @return string
	 */
	public function get_id() {
		return 'products';
	}

	/**
	 * Title.
	 *
	 * @return string
	 */
	public function get_title() {
		$onboarding_profile = get_option( OnboardingProfile::DATA_OPTION, array() );

		if ( isset( $onboarding_profile['business_choice'] ) && 'im_already_selling' === $onboarding_profile['business_choice'] ) {
			return __( 'Import your products', 'woocommerce' );
		}

		return __( 'Add your products', 'woocommerce' );
	}

	/**
	 * Content.
	 *
	 * @return string
	 */
	public function get_content() {
		return __(
			'Start by adding the first product to your store. You can add your products manually, via CSV, or import them from another service.',
			'woocommerce'
		);
	}

	/**
	 * Time.
	 *
	 * @return string
	 */
	public function get_time() {
		return __( '1 minute per product', 'woocommerce' );
	}

	/**
	 * Task completion.
	 *
	 * @return bool
	 */
	public function is_complete() {
		if ( $this->has_previously_completed() ) {
			return true;
		}

		return self::has_products();
	}

	/**
	 * Additional data.
	 *
	 * @return array
	 */
	public function get_additional_data() {
		return array(
			'has_products' => self::has_products(),
		);
	}

	/**
	 * If a task is always accessible, relevant for when a task list is hidden but a task can still be viewed.
	 *
	 * @return bool
	 */
	public function is_always_accessible() {
		return true;
	}

	/**
	 * Adds a return to task list notice when completing the import product task.
	 *
	 * @param string $hook Page hook.
	 */
	public function possibly_add_import_return_notice_script( $hook ) {
		$step = isset( $_GET['step'] ) ? $_GET['step'] : ''; // phpcs:ignore csrf ok, sanitization ok.

		if ( $hook !== 'product_page_product_importer' || $step !== 'done' ) {
			return;
		}

		if ( ! $this->is_active() || $this->is_complete() ) {
			return;
		}

		WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-product-import-notice', true );
	}

	/**
	 * Adds a return to task list notice when completing the loading sample products action.
	 *
	 * @param string $hook Page hook.
	 */
	public function possibly_add_load_sample_return_notice_script( $hook ) {
		if ( $hook !== 'edit.php' || get_query_var( 'post_type' ) !== 'product' ) {
			return;
		}

		$referer = wp_get_referer();
		if ( ! $referer || strpos( $referer, wc_admin_url() ) !== 0 ) {
			return;
		}

		if ( ! isset( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) ) {
			return;
		}

		$task_id = sanitize_title_with_dashes( wp_unslash( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) );
		if ( $task_id !== $this->get_id() || ! $this->is_complete() ) {
			return;
		}

		WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-load-sample-products-notice', true );
	}

	/**
	 * Set the has products transient if the post qualifies as a user created product.
	 *
	 * @param int $post_id Post ID.
	 */
	public function maybe_set_has_product_transient_on_untrashed_post( $post_id ) {
		if ( get_post_type( $post_id ) !== 'product' ) {
			return;
		}

		$this->maybe_set_has_product_transient( $post_id, wc_get_product( $post_id ) );
	}

	/**
	 * Set the has products transient if the product qualifies as a user created product.
	 *
	 * @param int        $product_id Product ID.
	 * @param WC_Product $product Product object.
	 */
	public function maybe_set_has_product_transient( $product_id, $product ) {
		if ( ! $this->has_previously_completed() && $this->is_valid_product( $product ) ) {
			set_transient( self::HAS_PRODUCT_TRANSIENT, 'yes' );
			$this->possibly_track_completion();
		}
	}

	/**
	 * Handle product trashing via the trashed_post hook.
	 *
	 * @param int $post_id Post ID.
	 * @return void
	 */
	public function on_product_trashed( $post_id ) {
		if ( get_post_type( $post_id ) !== 'product' ) {
			return;
		}

		$this->revert_task_completion();
	}

	/**
	 * Handle permanent product deletion via the deleted_post_product hook.
	 *
	 * @return void
	 */
	public function on_product_deleted() {
		$this->revert_task_completion();
	}

	/**
	 * Schedule a deferred check to revert task completion if no products remain.
	 *
	 * Uses the shutdown hook so that bulk operations (e.g. trashing many products
	 * at once) only trigger a single has_products() query instead of one per product.
	 *
	 * @return void
	 */
	private function revert_task_completion(): void {
		delete_transient( self::HAS_PRODUCT_TRANSIENT );

		if ( self::$revert_scheduled ) {
			return;
		}

		self::$revert_scheduled = true;
		add_action( 'shutdown', array( $this, 'maybe_revert_on_shutdown' ) );
	}

	/**
	 * Re-check whether valid products still exist and revert task completion if none remain.
	 *
	 * Runs once at the end of the request via the shutdown hook.
	 *
	 * @return void
	 */
	public function maybe_revert_on_shutdown(): void {
		self::$revert_scheduled = false;

		if ( self::has_products() ) {
			return;
		}

		$completed_tasks = get_option( self::COMPLETED_OPTION, array() );
		$task_id         = $this->get_id();

		if ( in_array( $task_id, $completed_tasks, true ) ) {
			$completed_tasks = array_values( array_diff( $completed_tasks, array( $task_id ) ) );
			update_option( self::COMPLETED_OPTION, $completed_tasks );
		}
	}

	/**
	 * Check if the product qualifies as a user created product.
	 *
	 * @param WC_Product $product Product object.
	 * @return bool
	 */
	private function is_valid_product( $product ) {
		return ProductStatus::PUBLISH === $product->get_status() &&
			( ! $product->get_meta( '_headstart_post' ) ||
			get_post_meta( $product->get_id(), '_edit_last', true ) );
	}

	/**
	 * Check if the store has any user created published products.
	 *
	 * @return bool
	 */
	public static function has_products() {
		$product_exists = get_transient( self::HAS_PRODUCT_TRANSIENT );
		if ( $product_exists ) {
			return 'yes' === $product_exists;
		}

		global $wpdb;

		/*
		 * Check if any valid products exist and return 'yes' or 'no'
		 * A valid product must:
		 * 1. Be a published product post type
		 * 2. Meet one of these conditions:
		 *    - Have been edited by a user (_edit_last meta exists), OR
		 *    - Not have _headstart_post meta, OR
		 *    - Have _headstart_post meta but it's NULL
		 */
		$value = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT IF(
					EXISTS (
						SELECT 1 FROM {$wpdb->posts} p
						WHERE p.post_type = %s
						AND p.post_status = %s
						AND (
							EXISTS (
								SELECT 1 FROM {$wpdb->postmeta} pm
								WHERE pm.post_id = p.ID
								AND pm.meta_key = %s
							)
							OR
							NOT EXISTS (
								SELECT 1 FROM {$wpdb->postmeta} pm
								WHERE pm.post_id = p.ID
								AND pm.meta_key = %s
							)
							OR
							EXISTS (
								SELECT 1 FROM {$wpdb->postmeta} pm
								WHERE pm.post_id = p.ID
								AND pm.meta_key = %s
								AND pm.meta_value = ''
							)
						)
						LIMIT 1
					),
					'yes', 'no'
				)",
				'product',
				ProductStatus::PUBLISH,
				'_edit_last',
				'_headstart_post',
				'_headstart_post'
			)
		);

		set_transient( self::HAS_PRODUCT_TRANSIENT, $value );
		return 'yes' === $value;
	}

	/**
	 * Redirect to the add product tasklist if there are no products.
	 *
	 * @return void
	 */
	public function maybe_redirect_to_add_product_tasklist() {
		$screen = get_current_screen();
		if ( $screen && 'edit' === $screen->base && 'product' === $screen->post_type ) {
			// wp_count_posts is cached.
			$counts = (array) wp_count_posts( $screen->post_type );
			unset( $counts['auto-draft'] );
			$count = array_sum( $counts );
			if ( $count > 0 ) {
				return;
			}
			wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&task=products' ) );
			exit;
		}
	}
}
