<?php
declare( strict_types=1 );

namespace FiboFilters\Indexer;

use FiboFilters\WP\Helper as WPHelper;

/**
 * BuilderUi Class
 */
class BuilderUI {
	const DETAILS_DISPLAY_KEY = 'fibofilters_indexer_details_display';

	/** @var BuildInfo */
	private $build_info;

	/** @var Config */
	private $config;

	/** @var Logger */
	private $logger;

	/** @var WPHelper */
	private $wp_helper;

	public function __construct( BuildInfo $build_info, Config $config, Logger $logger, WPHelper $wp_helper ) {
		$this->config     = $config;
		$this->build_info = $build_info;
		$this->logger     = $logger;
		$this->wp_helper  = $wp_helper;
	}

	public function refresh_status(): void {
		$status = $this->build_info->get_info( 'status', $this->config->get_index_role() );

		switch ( $status ) {
			case 'cancellation':
				$this->build_info->add_info( 'status', 'not-exist' );
				$this->logger->log( 'Canceling completed.' );
				break;
			case 'error':
				do_action( 'fibofilters/indexer/cancel', '', '', false );
				break;
		}
	}

	public function get_status_data(): array {
		$this->refresh_status();

		$data = [
			'loop'    => false,
			'info'    => [],
			'notices' => [],
		];

		foreach ( array_keys( $this->build_info->get_index_info_struct() ) as $key ) {
			$data['info'][ $key ] = $this->build_info->get_info( $key, $this->config->get_index_role() );
		}

		$data['is_parallel_building_enabled'] = $this->config->is_parallel_building_enabled();
		if ( $this->config->is_parallel_building_enabled() ) {
			foreach ( array_keys( $this->build_info->get_index_info_struct() ) as $key ) {
				$data['info'][ $key . '_main' ] = $this->build_info->get_info( $key, 'main' );
			}
		}

		if ( isset( $data['info']['status'] ) && in_array(
			$data['info']['status'],
			[
				'preparing',
				'building',
				'cancellation',
			],
			true
		) ) {
			$data['loop'] = true;
		}

		$data['progress'] = $this->get_progress_bar_value();

		$no_index_info      = '<b>' . _x( 'Filters status:', '[admin]', 'fibofilters' ) . '</b> ';
		$no_index_info     .= _x( "Your filters do not work because the index hasn't been built yet.", '[admin]', 'fibofilters' );
		$old_index_end_time = $this->wp_helper->local_date( absint( $this->build_info->get_info( 'end_ts', 'main' ) ), 'Y-m-d H:i:s' );

		if ( $this->config->is_parallel_building_enabled() && $this->build_info->get_info( 'status', 'tmp' ) !== 'completed' ) {
			$notice = [ 'status' => 'info' ];
			if ( $this->build_info->get_info( 'status', 'main' ) === 'completed' ) {
				$notice['content']  = '<b>' . _x( 'Filters status:', '[admin]', 'fibofilters' ) . '</b> ';
				$notice['content'] .= _x( 'We have some good news!', '[admin]', 'fibofilters' );
				if ( in_array( $this->build_info->get_info( 'status', 'tmp' ), [ 'preparing', 'building' ], true ) ) {
					$notice['content'] .= ' ' . _x( "Even though the current index is being built, it doesn't affect your filters.", '[admin]', 'fibofilters' );
				} else {
					$notice['content'] .= ' ' . _x( "Even though the current index wasn't built, it doesn't affect your filters.", '[admin]', 'fibofilters' );
				}
				/* translators: %s date and time */
				$notice['content'] .= ' ' . sprintf( _x( 'It works well based on the last properly built index from %s', '[admin]', 'fibofilters' ), $old_index_end_time );
			} else {
				$notice['status']  = 'warning';
				$notice['content'] = $no_index_info;
			}
			$data['notices'][] = $notice;
		}

		if ( ! $this->config->is_parallel_building_enabled() && $this->build_info->get_info( 'status', 'main' ) !== 'completed' ) {
			$data['notices'][] = [
				'status'  => 'warning',
				'content' => $no_index_info,
			];
		}

		return $data;
	}

	public function get_progress_bar_value(): int {
		if ( $this->build_info->get_info( 'status', $this->config->get_index_role() ) === 'completed' ) {
			return 100;
		}

		$percent = $this->get_filters_progress();

		$progress = apply_filters( 'fibofilters/indexer/process_status/progress', $percent );

		return absint( $progress ) > 100 ? 99 : $progress;
	}

	public function get_filters_progress(): int {
		$percent     = 0;
		$total_items = absint( $this->build_info->get_info( 'total_products_for_indexing', $this->config->get_index_role() ) );
		$processed   = absint( $this->build_info->get_info( 'filters_processed', $this->config->get_index_role() ) );

		if (
			! empty( $total_items ) &&
			is_numeric( $total_items ) &&
			! empty( $processed ) &&
			is_numeric( $processed )
		) {
			$percent = $processed * 100 / $total_items;
		}

		return absint( $percent );
	}

	/**
	 * Remove all database tables created by this plugin
	 *
	 * @param bool $network_scope Delete tables in whole network.
	 */
	public function delete_index_options( bool $network_scope = false ): void {
		global $wpdb;

		$prefix = $wpdb->prefix;

		if ( is_multisite() && $network_scope ) {
			$prefix = $wpdb->base_prefix;
		}

		$last_build_option_key = $wpdb->esc_like( BuildInfo::LAST_BUILD_OPTION_KEY ) . '%';
		$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->options WHERE option_name LIKE %s", $last_build_option_key ) );
		delete_transient( self::DETAILS_DISPLAY_KEY );

		if ( is_multisite() && $network_scope ) {
			foreach ( get_sites() as $site ) {
				if ( is_numeric( $site->blog_id ) ) {
					$blog_id = (int) $site->blog_id === 1 ? '' : $site->blog_id . '_';

					$table = $prefix . $blog_id . 'options';

					$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE option_name LIKE %s", $last_build_option_key ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared

					$wpdb->delete( $table, [ 'option_name' => '_transient_timeout_' . self::DETAILS_DISPLAY_KEY ] );
					$wpdb->delete( $table, [ 'option_name' => '_transient_' . self::DETAILS_DISPLAY_KEY ] );
				}
			}
		}
	}
}
