<?php
/**
 * Interface d'administration.
 *
 * @package CVS
 * @license GPL-2.0-or-later
 */

defined( 'ABSPATH' ) || exit;

class CVS_Admin {

	const FALLBACK_SLUG = 'core-version-switcher-by-volade';

	const USER_META_INTRO_COLLAPSED = 'cvs_intro_collapsed';

	/** @var CVS_Plugin */
	private $plugin;

	public function __construct( CVS_Plugin $plugin ) {
		$this->plugin = $plugin;

		add_action( 'volade_register_plugins', array( $this, 'register_volade_menu' ), 10 );
		add_action( 'plugins_loaded', array( $this, 'register_volade_menu' ), 5 );
		add_action( 'admin_menu', array( $this, 'register_menu' ), 11 );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
		add_action( 'admin_post_cvs_save_settings', array( $this, 'handle_save' ) );
		add_action( 'admin_post_cvs_clear_target', array( $this, 'handle_clear_target' ) );
		add_action( 'admin_post_cvs_apply_preset', array( $this, 'handle_apply_preset' ) );
		add_action( 'admin_post_cvs_clear_updater_lock', array( $this, 'handle_clear_lock' ) );
		add_action( 'admin_post_cvs_refresh_releases', array( $this, 'handle_refresh_releases' ) );
		add_action( 'admin_post_cvs_export_settings', array( $this, 'handle_export' ) );
		add_action( 'admin_post_cvs_import_settings', array( $this, 'handle_import' ) );
		add_action( 'admin_post_cvs_settings_source', array( $this, 'handle_settings_source' ) );
		add_action( 'wp_ajax_cvs_save_intro_collapsed', array( $this, 'ajax_save_intro_collapsed' ) );
		add_action( 'admin_notices', array( $this, 'conflict_admin_notice' ) );

		if ( is_multisite() ) {
			add_action( 'network_admin_notices', array( $this, 'network_admin_notice' ) );
		}

		add_filter( 'plugin_action_links_' . plugin_basename( CVS_FILE ), array( $this, 'plugin_action_links' ) );
	}

	public function has_volade_sdk() {
		return class_exists( 'Volade_SDK' ) && Volade_SDK::get_instance();
	}

	public function uses_volade_menu() {
		return $this->has_volade_sdk();
	}

	public function plugin_action_links( $links ) {
		$url = admin_url( $this->settings_url( false ) );
		array_unshift(
			$links,
			'<a href="' . esc_url( $url ) . '">' . esc_html__( 'Settings', 'core-version-switcher-by-volade' ) . '</a>'
		);
		return $links;
	}

	public function register_volade_menu() {
		$sdk = $this->uses_volade_menu() ? Volade_SDK::get_instance() : null;
		if ( ! $sdk ) {
			return;
		}

		$sdk->register_plugin_submenu(
			CVS_SLUG,
			__( 'Core Version Switcher by Volade', 'core-version-switcher-by-volade' ),
			__( 'Core Version', 'core-version-switcher-by-volade' ),
			array( $this, 'render_page' )
		);
	}

	public function register_menu() {
		if ( $this->uses_volade_menu() ) {
			return;
		}

		add_options_page(
			__( 'Core Version Switcher by Volade', 'core-version-switcher-by-volade' ),
			__( 'Core Version', 'core-version-switcher-by-volade' ),
			'update_core',
			self::FALLBACK_SLUG,
			array( $this, 'render_page' )
		);
	}

	public function page_slug() {
		return $this->uses_volade_menu() ? Volade_SDK::get_plugin_page_slug( CVS_SLUG ) : self::FALLBACK_SLUG;
	}

	public static function instance_settings_path( CVS_Plugin $plugin = null ) {
		$admin = $plugin ? $plugin->admin : null;
		if ( $admin && $admin->uses_volade_menu() ) {
			return $admin->settings_url( false );
		}
		return 'options-general.php?page=' . self::FALLBACK_SLUG;
	}

	public static function is_intro_collapsed( $user_id = 0 ) {
		$user_id = $user_id ?: get_current_user_id();
		if ( ! $user_id ) {
			return false;
		}
		return (bool) get_user_meta( $user_id, self::USER_META_INTRO_COLLAPSED, true );
	}

	public function ajax_save_intro_collapsed() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_send_json_error();
		}
		check_ajax_referer( 'cvs_intro_collapsed', 'nonce' );
		$collapsed = ! empty( $_POST['collapsed'] );
		update_user_meta( get_current_user_id(), self::USER_META_INTRO_COLLAPSED, $collapsed ? 1 : 0 );
		wp_send_json_success();
	}

	/**
	 * @param string $action
	 * @param bool   $is_network
	 */
	public static function action_url( $action, $is_network = false ) {
		if ( $is_network ) {
			return network_admin_url( 'edit.php?action=' . $action );
		}
		return admin_url( 'admin-post.php?action=' . $action );
	}

	private function settings_url( $with_updated = true, $extra = array() ) {
		unset( $with_updated );
		if ( $this->uses_volade_menu() ) {
			$args = array_merge( array( 'page' => $this->page_slug() ), $extra );
			return 'admin.php?' . http_build_query( $args );
		}
		$args = array_merge( array( 'page' => self::FALLBACK_SLUG ), $extra );
		return 'options-general.php?' . http_build_query( $args );
	}

	public function enqueue_assets( $hook ) {
		$allowed_hooks = array(
			'volade_page_' . $this->page_slug(),
			'toplevel_page_volade',
			'settings_page_' . self::FALLBACK_SLUG,
			'settings_page_' . CVS_Network_Admin::PAGE_SLUG,
		);

		if ( ! in_array( $hook, $allowed_hooks, true ) ) {
			return;
		}

		wp_enqueue_style( 'cvs-admin', CVS_URL . 'assets/css/admin.css', array(), CVS_VERSION );
		wp_enqueue_script( 'cvs-admin', CVS_URL . 'assets/js/admin.js', array(), CVS_VERSION, true );
		wp_localize_script(
			'cvs-admin',
			'cvsAdmin',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'cvs_intro_collapsed' ),
			)
		);
	}

	public function handle_save() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_save_settings' );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in CVS_Settings::sanitize().
		$input = wp_unslash( $_POST['cvs'] ?? array() );
		if ( ! is_array( $input ) ) {
			$input = array();
		}

		if ( $this->plugin->settings->is_site_readonly() ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'cvs_error' => 'readonly' ) ) ) );
			exit;
		}

		$old_target = CVS_Settings::sanitize_version( $this->plugin->settings->get( 'target_version' ) );
		$new_target = CVS_Settings::sanitize_version( $input['target_version'] ?? '' );

		$valid = $this->plugin->settings->validate_target( $new_target, $input );
		if ( is_wp_error( $valid ) ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'cvs_error' => rawurlencode( $valid->get_error_message() ) ) ) ) );
			exit;
		}

		if ( $new_target && $new_target !== $old_target ) {
			$this->plugin->settings->remember_previous_version();
			$this->plugin->settings->mark_pin_set();
		}

		$this->plugin->settings->save( $input, 'site' );

		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'updated' => '1' ) ) ) );
		exit;
	}

	public function handle_apply_preset() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_apply_preset' );
		$slug    = sanitize_key( wp_unslash( $_POST['cvs_preset'] ?? '' ) );
		$version = CVS_Presets::resolve( $slug, $this->plugin );

		if ( is_wp_error( $version ) ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'preset_error' => '1' ) ) ) );
			exit;
		}

		$valid = $this->plugin->settings->validate_target( $version );
		if ( is_wp_error( $valid ) ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'cvs_error' => rawurlencode( $valid->get_error_message() ) ) ) ) );
			exit;
		}

		$this->plugin->settings->remember_previous_version();
		$this->plugin->settings->mark_pin_set();
		$settings                   = $this->plugin->settings->all();
		$settings['target_version'] = $version;
		$this->plugin->settings->save( $settings, 'site' );

		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'preset_applied' => '1' ) ) ) );
		exit;
	}

	public function handle_clear_lock() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_clear_updater_lock' );
		delete_option( 'core_updater.lock' );
		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'lock_cleared' => '1' ) ) ) );
		exit;
	}

	public function handle_refresh_releases() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_refresh_releases' );
		CVS_Releases::fetch_stable_map( true );
		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'releases_refreshed' => '1' ) ) ) );
		exit;
	}

	public function handle_clear_target() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_clear_target' );
		$this->plugin->settings->clear_target( 'site' );
		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'cleared' => '1' ) ) ) );
		exit;
	}

	public function handle_export() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_export_settings' );

		$json = $this->plugin->settings->export_json( 'site' );
		$name = 'cvs-settings-' . gmdate( 'Y-m-d' ) . '.json';

		nocache_headers();
		header( 'Content-Type: application/json; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . $name . '"' );
		echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		exit;
	}

	public function handle_import() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_import_settings' );

		if ( empty( $_FILES['cvs_import_file']['tmp_name'] ) ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'import_error' => '1' ) ) ) );
			exit;
		}

		$raw    = file_get_contents( sanitize_text_field( wp_unslash( $_FILES['cvs_import_file']['tmp_name'] ) ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
		$result = $this->plugin->settings->import_data( $raw, 'site' );

		if ( is_wp_error( $result ) ) {
			wp_safe_redirect( admin_url( $this->settings_url( false, array( 'import_error' => '1' ) ) ) );
			exit;
		}

		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'imported' => '1' ) ) ) );
		exit;
	}

	public function handle_settings_source() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		check_admin_referer( 'cvs_settings_source' );
		$source = sanitize_key( wp_unslash( $_POST['cvs_source'] ?? 'local' ) );
		$this->plugin->settings->set_settings_source( $source );

		wp_safe_redirect( admin_url( $this->settings_url( false, array( 'source_updated' => '1' ) ) ) );
		exit;
	}

	public function conflict_admin_notice() {
		if ( ! current_user_can( 'update_core' ) ) {
			return;
		}

		$conflicts = CVS_Settings::detect_conflicts();
		if ( empty( $conflicts ) ) {
			return;
		}

		$names = wp_list_pluck( $conflicts, 'name' );
		echo '<div class="notice notice-warning"><p>';
		echo esc_html(
			sprintf(
				/* translators: %s: plugin names */
				__( 'Core Version Switcher: deactivate %s to avoid conflicting version pins.', 'core-version-switcher-by-volade' ),
				implode( ', ', $names )
			)
		);
		echo '</p></div>';
	}

	public function network_admin_notice() {
		if ( ! current_user_can( 'manage_network_options' ) || ! is_main_site() ) {
			return;
		}
		$url = CVS_Network_Admin::settings_url();
		echo '<div class="notice notice-info"><p>';
		printf(
			/* translators: %s: settings URL */
			esc_html__( 'Multisite: network-wide core version policy is available under %s.', 'core-version-switcher-by-volade' ),
			'<a href="' . esc_url( $url ) . '">' . esc_html__( 'Settings → Core Version (network)', 'core-version-switcher-by-volade' ) . '</a>'
		);
		echo '</p></div>';
	}

	public function render_page() {
		if ( ! current_user_can( 'update_core' ) ) {
			wp_die( esc_html__( 'Access denied.', 'core-version-switcher-by-volade' ) );
		}

		$settings     = $this->plugin->settings->all();
		$context      = 'site';
		$is_readonly  = $this->plugin->settings->is_site_readonly();
		$target       = CVS_Settings::sanitize_version( $settings['target_version'] ?? '' );
		$zip_url      = $target ? $this->plugin->settings->build_download_url( $target ) : '';
		$zip_ok       = $zip_url ? $this->plugin->settings->zip_exists( $zip_url ) : null;
		$log          = $this->plugin->settings->get_log();
		$presets      = CVS_Presets::all( $this->plugin );
		$releases     = CVS_Releases::get_recent_releases( 60, ! empty( $settings['show_insecure_in_picker'] ) );
		$diagnostics  = $this->plugin->diagnostics->run();
		$insights     = $target ? $this->plugin->settings->get_target_insights( $target ) : array();
		$rollback     = CVS_Settings::sanitize_version( get_option( CVS_Settings::PREVIOUS_VERSION_KEY, '' ) );
		$latest       = CVS_Releases::get_latest_version();
		$compat       = $target ? CVS_Preflight::compat_report( $target ) : array(
			'errors'   => array(),
			'warnings' => array(),
			'scan'     => array(
				'plugins' => array(),
				'themes'  => array(),
			),
		);
		$checksum     = CVS_Checksums::get_last_result();
		$pin_expires  = $this->plugin->settings->pin_expires_at();
		$access       = $this->plugin->volade ? $this->plugin->volade->get_access_level() : 'guest';
		$access_label = $this->plugin->volade ? $this->plugin->volade->get_access_level_label( $access ) : __( 'No account', 'core-version-switcher-by-volade' );

		include CVS_DIR . 'admin/views/settings-page.php';
	}
}
