<?php
/**
 * Core plugin loader.
 *
 * Registers the Gravity Forms add-on at the correct point in the load order
 * (the gform_loaded hook, which fires only when Gravity Forms is active),
 * loads shared components, and shows a notice when Gravity Forms is missing.
 *
 * @package DrezSync
 */

defined( 'ABSPATH' ) || exit;

/**
 * Main plugin class.
 */
final class DrezSync {

	/**
	 * Single instance.
	 *
	 * @var DrezSync|null
	 */
	private static $instance = null;

	/**
	 * Google Calendar connection.
	 *
	 * @var DrezSync_Connection
	 */
	public $connection;

	/**
	 * Connection screen and OAuth handlers.
	 *
	 * @var DrezSync_Connect
	 */
	public $connect;

	/**
	 * Return the single instance, creating it on first call.
	 *
	 * Hooked to gform_loaded, so by the time this runs Gravity Forms is
	 * present and its add-on framework is available.
	 *
	 * @return DrezSync
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Wire everything up.
	 */
	private function __construct() {
		$this->load();
		$this->migrate_legacy_options();
		add_action( 'init', array( $this, 'load_textdomain' ) );
		$this->register_addon();
	}

	/**
	 * Carry the Google connection across the rename in 1.6.7.
	 *
	 * The plugin was called SlotSync before 1.6.7 and stored its credentials and
	 * OAuth token under slotsync_* option names. Those two options are the only
	 * stored data worth rescuing: losing them means redoing the entire Google
	 * OAuth setup by hand. The stored values are encrypted against the site's own
	 * salts rather than the option name, so copying them across is enough.
	 *
	 * Booking fields are deliberately NOT migrated. The old name never had a
	 * public WordPress.org release, so there is no install base to carry forward,
	 * and rewriting every form's stored JSON to change a field type is real risk
	 * for no one's benefit. A site that somehow ran the old build re-adds its
	 * booking field, which is a two minute job.
	 *
	 * Runs from the constructor rather than an admin hook because the front end
	 * needs the token too, so waiting for a dashboard visit would break booking
	 * on a site nobody had logged into yet. The guard is a single autoloaded
	 * option read, and it is the flag that stops this, not the absence of the old
	 * options, so a site that deliberately disconnects is never re-migrated.
	 */
	private function migrate_legacy_options() {
		if ( get_option( 'drezsync_migrated' ) ) {
			return;
		}
		update_option( 'drezsync_migrated', DREZSYNC_VERSION );

		$legacy = array(
			'slotsync_google_credentials' => DrezSync_Connection::OPTION_CREDENTIALS,
			'slotsync_google_token'       => DrezSync_Connection::OPTION_TOKEN,
		);

		foreach ( $legacy as $old_key => $new_key ) {
			$value = get_option( $old_key );
			if ( false !== $value && false === get_option( $new_key ) ) {
				update_option( $new_key, $value, false );
			}
			delete_option( $old_key );
		}
	}

	/**
	 * Load class files and construct shared components.
	 */
	private function load() {
		require_once DREZSYNC_DIR . 'includes/google/class-connection.php';
		$this->connection = new DrezSync_Connection();

		require_once DREZSYNC_DIR . 'includes/admin/class-connect.php';
		$this->connect = new DrezSync_Connect( $this->connection );

		require_once DREZSYNC_DIR . 'includes/field/class-field-frontend.php';
		new DrezSync_Field_Frontend( $this->connection );
	}

	/**
	 * Register the Gravity Forms add-on.
	 */
	public function register_addon() {
		if ( ! method_exists( 'GFForms', 'include_addon_framework' ) ) {
			return;
		}
		GFForms::include_addon_framework();
		require_once DREZSYNC_DIR . 'includes/class-gf-addon.php';
		GFAddOn::register( 'DrezSync_GF_Addon' );

		if ( class_exists( 'GF_Fields' ) ) {
			require_once DREZSYNC_DIR . 'includes/field/class-booking-field.php';
			GF_Fields::register( new DrezSync_Booking_Field() );

			require_once DREZSYNC_DIR . 'includes/field/class-field-settings.php';
			new DrezSync_Field_Settings();

			// Pro feature modules. This directory is removed from the free build,
			// so the free plugin simply never loads them.
			foreach ( (array) glob( DREZSYNC_DIR . 'includes/pro/*.php' ) as $pro_file ) {
				require_once $pro_file;
			}
		}
	}

	/**
	 * Load translations.
	 */
	public function load_textdomain() {
	}

	/**
	 * Show an admin notice when Gravity Forms isn't active.
	 */
	public static function maybe_dependency_notice() {
		if ( class_exists( 'GFForms' ) ) {
			return;
		}
		echo '<div class="notice notice-warning"><p>';
		esc_html_e( 'DrezSync needs Gravity Forms installed and active to run.', 'drezsync' );
		echo '</p></div>';
	}
}
