<?php

namespace SugarCalendarBookings\Support\Database;

use SugarCalendarBookings\Support\RequestType;
use SugarCalendarBookings\Support\Bootable;
use WP_Upgrader;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Database.
 *
 * @since 1.0.0
 */
class Database implements Bootable {

	/**
	 * List of migrations instances.
	 *
	 * @since 1.0.0
	 *
	 * @var AbstractTableMigration[]
	 */
	private $migrations;

	/**
	 * Initialize.
	 *
	 * @since 1.0.0
	 */
	public function init() {

		$this->define_tables();
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.0.0
	 */
	public function hooks() {

		if ( sugar_calendar_bookings()->get( RequestType::class )->is_admin() ) {
			add_action( 'admin_init', [ $this, 'validate_db' ] );
		}

		// Validate DB after plugin upgrade.
		add_action( 'upgrader_process_complete', [ $this, 'validate_db_after_upgrade' ], PHP_INT_MAX, 2 );
		add_action( 'wp_ajax_nopriv_scbookings_validate_db', [ $this, 'validate_db_ajax_handler' ] );
	}

	/**
	 * Register migrations.
	 *
	 * @since 1.0.0
	 *
	 * @param array<class-string<AbstractTableMigration>> $migration_classes List of migration classes.
	 */
	public function register_migrations( $migration_classes ) {

		foreach ( $migration_classes as $migration_class ) {
			$this->migrations[] = new $migration_class();
		}
	}

	/**
	 * Check DB version and update to the latest one.
	 *
	 * @since 1.0.0
	 */
	public function validate_db() {

		foreach ( $this->migrations as $migration ) {
			if ( $migration->is_enabled() ) {
				$migration->validate_db();
			}
		}
	}

	/**
	 * Validate DB after plugin update.
	 * Initiate ajax call to perform the migrations with the new plugin version code.
	 *
	 * @since 1.0.0
	 *
	 * @param WP_Upgrader $upgrader WP_Upgrader instance.
	 * @param array       $options  Array of update data.
	 */
	public function validate_db_after_upgrade( $upgrader, $options ) {

		$request_type = sugar_calendar_bookings()->get( RequestType::class );

		if (
			// Skip if in admin panel.
			$request_type->is_admin() ||
			// Skip if it's update from plugins list page.
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			( $request_type->is_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'update-plugin' )
		) {
			return;
		}

		$plugins = [];

		if ( isset( $options['plugins'] ) && is_array( $options['plugins'] ) ) {
			$plugins = $options['plugins'];
		} elseif ( isset( $options['plugin'] ) && is_string( $options['plugin'] ) ) {
			$plugins = [ $options['plugin'] ];
		}

		if ( ! in_array( plugin_basename( SCBOOKINGS_PLUGIN_FILE ), $plugins, true ) ) {
			return;
		}

		$url = add_query_arg(
			[
				'action' => 'scbookings_validate_db',
			],
			admin_url( 'admin-ajax.php' )
		);

		$timeout = (int) ini_get( 'max_execution_time' );

		$args = [
			'sslverify' => false,
			'timeout'   => $timeout ? $timeout : 30,
		];

		wp_remote_post( $url, $args );
	}

	/**
	 * Initialize migrations via AJAX request.
	 *
	 * @since 1.0.0
	 */
	public function validate_db_ajax_handler() {

		$this->validate_db();

		wp_send_json_success();
	}

	/**
	 * Register custom tables within `$wpdb` object.
	 *
	 * @since 1.0.0
	 */
	private function define_tables() {

		global $wpdb;

		foreach ( $this->migrations as $migration ) {
			$table_name        = $migration->get_raw_table_name();
			$wpdb->$table_name = $wpdb->prefix . $table_name;
			$wpdb->tables[]    = $table_name;
		}
	}
}
