<?php
/**
 * Main plugin coordinator.
 *
 * @package SubmissionInbox
 */

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

// phpcs:disable PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Loading the plugin text domain keeps translations available on older WordPress versions and is harmless on modern WordPress.

/**
 * Coordinates plugin services.
 */
class SUBIN_Plugin {
	/**
	 * Settings repository.
	 *
	 * @var SUBIN_SettingsRepository
	 */
	private $settings;

	/**
	 * SMTP mailer.
	 *
	 * @var \SUBIN\Mailer\SmtpMailer
	 */
	private $smtp_mailer;

	/**
	 * Form submission context.
	 *
	 * @var \SUBIN\Forms\FormSubmissionContext
	 */
	private $form_context;

	/**
	 * Mail logger.
	 *
	 * @var \SUBIN\MailLog\MailLogger
	 */
	private $mail_logger;

	/**
	 * Contact Form 7 integration.
	 *
	 * @var \SUBIN\Forms\ContactForm7Integration
	 */
	private $contact_form_7;

	/**
	 * WPForms integration.
	 *
	 * @var \SUBIN\Forms\WPFormsIntegration
	 */
	private $wpforms;

	/**
	 * Fluent Forms integration.
	 *
	 * @var \SUBIN\Forms\FluentFormsIntegration
	 */
	private $fluent_forms;

	/**
	 * Forminator integration.
	 *
	 * @var \SUBIN\Forms\ForminatorIntegration
	 */
	private $forminator;

	/**
	 * Ninja Forms integration.
	 *
	 * @var \SUBIN\Forms\NinjaFormsIntegration
	 */
	private $ninja_forms;

	/**
	 * Retention service.
	 *
	 * @var \SUBIN\Retention\RetentionService
	 */
	private $retention;

	/**
	 * Built-in form shortcode.
	 *
	 * @var \SUBIN\Forms\FormShortcode
	 */
	private $form_shortcode;

	/**
	 * Built-in form location cache coordinator.
	 *
	 * @var \SUBIN\Forms\FormLocationService
	 */
	private $form_locations;

	/**
	 * Built-in form submission handler.
	 *
	 * @var \SUBIN\Forms\FormSubmissionHandler
	 */
	private $form_submission_handler;

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function run() {
		$this->settings     = new SUBIN_SettingsRepository();
		$this->form_context = new \SUBIN\Forms\FormSubmissionContext();
		add_action( SUBIN_Database::NOTE_ACTIVITY_REDACTION_HOOK, array( 'SUBIN_Database', 'continue_note_privacy_migrations' ) );
		add_action( SUBIN_Database::MAIL_EVENT_AUDIT_HOOK, array( 'SUBIN_Database', 'continue_mail_event_audit_backfill' ) );
		if ( false !== get_option( SUBIN_Database::MAIL_EVENT_AUDIT_CURSOR_OPTION, false ) && ! (bool) get_option( SUBIN_Database::MAIL_EVENT_AUDIT_COMPLETE_OPTION, false ) ) {
			SUBIN_Database::schedule_mail_event_audit_backfill();
		}
		add_action( 'subin_mail_event_status_updated', array( '\SUBIN\Mail\EmailHealthService', 'invalidate_signal_cache' ), 20 );
		add_action( 'subin_mail_event_no_email_generated', array( '\SUBIN\Mail\EmailHealthService', 'invalidate_signal_cache' ), 20 );
		add_action( 'subin_mail_event_metadata_updated', array( '\SUBIN\Mail\EmailHealthService', 'invalidate_signal_cache' ), 20 );
		add_action( 'subin_email_health_verification_updated', array( '\SUBIN\Mail\EmailHealthService', 'invalidate_signal_cache' ), 20 );

		$lead_repository       = new \SUBIN\Leads\LeadRepository();
		$lead_field_repository = new \SUBIN\Leads\LeadFieldRepository();
		$lead_capture           = new \SUBIN\Leads\LeadCaptureService( $lead_repository, $lead_field_repository );
		$form_repository       = new \SUBIN\Forms\FormRepository();
		$form_field_repository = new \SUBIN\Forms\FormFieldRepository();
		$form_analytics        = new \SUBIN\Forms\FormAnalyticsService( new \SUBIN\Forms\FormAnalyticsRepository(), $form_repository );
		$mail_event_repository  = new \SUBIN\MailLog\MailEventRepository();
		$email_log_exports       = new \SUBIN\MailLog\EmailLogExportService(
			$mail_event_repository,
			new \SUBIN\MailLog\MailEventPresenter()
		);
		$email_log_exports->register();
		$lead_mail_status       = new \SUBIN\Mail\LeadEmailStatusService( $lead_repository, $mail_event_repository );
		$form_analytics->register();
		$lead_mail_status->register();

		$notification_jobs      = new \SUBIN\Notifications\NotificationJobRepository();
		$submission_limiter     = new \SUBIN\Forms\SubmissionRateLimiter();
		$submission_receipts    = new \SUBIN\Forms\SubmissionReceiptRepository();
		$submission_acceptance  = new \SUBIN\Forms\SubmissionAcceptanceService(
			$submission_receipts,
			$lead_repository,
			$lead_field_repository,
			$notification_jobs
		);
		$sync_event_recorder    = new \SUBIN\Sync\SyncEventRecorder();
		$sync_event_recorder->register();
		$cloud_sync_service     = new \SUBIN\Cloud\CloudSyncService();
		$cloud_sync_service->register();
		$auto_reply_templates  = new \SUBIN\AutoReplies\AutoReplyTemplateRepository();
		$auto_reply_rules      = new \SUBIN\AutoReplies\AutoReplyRuleRepository();
		$auto_reply_renderer   = new \SUBIN\AutoReplies\AutoReplyMergeTagRenderer();
		$auto_reply_policy     = new \SUBIN\AutoReplies\AutoReplyPolicyService(
			$auto_reply_rules,
			$auto_reply_templates,
			new \SUBIN\AutoReplies\AutoReplyFormProviderRegistry( $form_repository, $form_field_repository ),
			new \SUBIN\AutoReplies\AutoReplyConditionEngine(),
			$auto_reply_renderer,
			$this->form_context
		);
		$auto_reply_rule_sender = new \SUBIN\AutoReplies\AutoReplyRuleSender( $auto_reply_rules, $auto_reply_templates, $mail_event_repository, $this->form_context, $notification_jobs, $auto_reply_renderer, $lead_repository );

		$this->form_submission_handler = new \SUBIN\Forms\FormSubmissionHandler(
			$this->settings,
			$form_repository,
			$form_field_repository,
			$lead_repository,
			$lead_field_repository,
			$this->form_context,
			new \SUBIN\AutoReplies\AutoReplySender( $auto_reply_templates, $mail_event_repository, $this->form_context, $form_field_repository, $auto_reply_rules, $auto_reply_renderer ),
			$mail_event_repository,
			new \SUBIN\Forms\RecaptchaVerifier( $this->settings ),
			$lead_capture,
			$notification_jobs,
			$submission_limiter,
			$submission_acceptance
		);
		$this->form_submission_handler->register();

		$this->form_shortcode = new \SUBIN\Forms\FormShortcode(
			$form_repository,
			$form_field_repository,
			new \SUBIN\Forms\FormRenderer( $this->settings, $form_analytics ),
			$this->form_submission_handler
		);
		$this->form_shortcode->register();

		$this->form_locations = new \SUBIN\Forms\FormLocationService();
		$this->form_locations->register();

		$this->smtp_mailer = new \SUBIN\Mailer\SmtpMailer( $this->settings, $this->form_context );
		$this->smtp_mailer->register();

		$this->mail_logger = new \SUBIN\MailLog\MailLogger(
			$mail_event_repository,
			$lead_repository,
			$this->form_context,
			$this->settings
		);
		$this->mail_logger->register();

		$this->contact_form_7 = new \SUBIN\Forms\ContactForm7Integration(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$this->form_context,
			$auto_reply_rule_sender,
			$lead_capture
		);
		$this->contact_form_7->register();

		$this->wpforms = new \SUBIN\Forms\WPFormsIntegration(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$this->form_context,
			$auto_reply_rule_sender,
			$lead_capture
		);
		$this->wpforms->register();

		$this->fluent_forms = new \SUBIN\Forms\FluentFormsIntegration(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$this->form_context,
			$auto_reply_rule_sender,
			$lead_capture
		);
		$this->fluent_forms->register();

		$this->forminator = new \SUBIN\Forms\ForminatorIntegration(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$this->form_context,
			$auto_reply_rule_sender,
			$lead_capture
		);
		$this->forminator->register();

		$this->ninja_forms = new \SUBIN\Forms\NinjaFormsIntegration(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$this->form_context,
			$auto_reply_rule_sender,
			$lead_capture
		);
		$this->ninja_forms->register();

		$this->retention = new \SUBIN\Retention\RetentionService(
			$this->settings,
			$lead_repository,
			$lead_field_repository,
			$mail_event_repository,
			$notification_jobs,
			$submission_receipts
		);
		$this->retention->register();

		add_action( 'init', array( $this, 'load_textdomain' ) );
		add_action( 'admin_init', array( $this, 'maybe_upgrade_database' ) );
		add_action( 'remove_user_from_blog', array( $this, 'forget_removed_user_team_access' ), 10, 1 );
		add_action( 'deleted_user', array( $this, 'forget_removed_user_team_access' ), 10, 1 );

		if ( is_admin() ) {
			$auto_reply_ajax = new \SUBIN\Admin\AutoReplyAjaxController( $auto_reply_policy );
			$auto_reply_ajax->register();

			$forms_ajax_page = new SUBIN_FormsPage();
			add_action( 'wp_ajax_subin_save_grapesjs_project', array( $forms_ajax_page, 'ajax_save_grapesjs_project' ) );
			add_action( 'wp_ajax_subin_save_grapesjs_draft', array( $forms_ajax_page, 'ajax_save_grapesjs_draft' ) );
			add_action( 'wp_ajax_subin_publish_grapesjs_draft', array( $forms_ajax_page, 'ajax_publish_grapesjs_draft' ) );
			add_action( 'wp_ajax_subin_restore_grapesjs_revision', array( $forms_ajax_page, 'ajax_restore_grapesjs_revision' ) );
			add_action( 'wp_ajax_subin_form_preflight', array( $forms_ajax_page, 'ajax_design_studio_preflight' ) );
			add_action( 'wp_ajax_subin_form_sandbox', array( $forms_ajax_page, 'ajax_design_studio_sandbox' ) );
			add_action( 'wp_ajax_subin_upload_design_studio_media', array( $forms_ajax_page, 'ajax_upload_design_studio_media' ) );

			$admin_menu = new SUBIN_AdminMenu( $this->settings, $this->form_context );
			$admin_menu->register();
		}
	}

	/**
	 * Load translations.
	 *
	 * @return void
	 */
	public function load_textdomain() {
		load_plugin_textdomain(
			SUBIN_PLUGIN_TEXT_DOMAIN,
			false,
			dirname( plugin_basename( SUBIN_PLUGIN_FILE ) ) . '/languages'
		);
	}

	/**
	 * Upgrade database schema only when the stored version is behind.
	 *
	 * @return void
	 */
	public function maybe_upgrade_database() {
		SUBIN_Database::maybe_upgrade();
		SUBIN_Database::continue_note_privacy_migrations();
	}

	/**
	 * Remove stale site-local access state when WordPress removes a user.
	 *
	 * WordPress owns the capability cleanup. The Team service only forgets its
	 * baseline ledger so a later re-add cannot inherit an obsolete assignment.
	 *
	 * @param int $user_id Removed WordPress user id.
	 * @return void
	 */
	public function forget_removed_user_team_access( $user_id ) {
		\SUBIN\Security\TeamAccessService::forget_user( $user_id );
	}
}
