<?php
/**
 * Emergency lockdown mode.
 *
 * @package ZA_Creative_Login_Shield
 */

defined( 'ABSPATH' ) || exit;

/**
 * Handles emergency lockdown mode to prevent all login attempts except whitelisted IPs.
 */
class ZACLS_Emergency {

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->register_hooks();
	}

	/**
	 * Register hooks.
	 */
	private function register_hooks() {
		add_filter( 'authenticate', array( $this, 'check_lockdown' ), 1, 3 );
		add_action( 'admin_notices', array( $this, 'show_lockdown_notice' ) );
	}

	/**
	 * Check if lockdown is active and block login if needed.
	 *
	 * @param mixed  $user     User object or null.
	 * @param string $username Username.
	 * @param string $password Password.
	 * @return WP_Error|mixed
	 */
	public function check_lockdown( $user, $username, $password ) {
		if ( ! $this->is_lockdown_active() ) {
			return $user;
		}

		$ip = ZACLS_Main::get_ip();

		if ( $this->is_ip_whitelisted( $ip ) ) {
			return $user;
		}

		return new WP_Error(
			'lockdown_active',
			esc_html__( 'Login is temporarily disabled due to emergency lockdown. Please try again later.', 'za-creative-login-shield' )
		);
	}

	/**
	 * Check if lockdown mode is active.
	 *
	 * @return bool
	 */
	public static function is_lockdown_active() {
		$lockdown = self::get_lockdown_data();
		return (bool) $lockdown;
	}

	/**
	 * Get the lockdown data (cached).
	 *
	 * @return object|null
	 */
	private static function get_lockdown_data() {
		$cached = wp_cache_get( 'zacls_lockdown_data', 'zacls' );
		if ( false !== $cached ) {
			return $cached;
		}

		global $wpdb;

		$table_name = $wpdb->prefix . 'zacls_lockdown';
		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) !== $table_name ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
			wp_cache_set( 'zacls_lockdown_data', false, 'zacls' );
			return null;
		}

		$data = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
			"SELECT * FROM {$table_name} WHERE is_active = 1 LIMIT 1" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		);

		wp_cache_set( 'zacls_lockdown_data', $data, 'zacls' );
		return $data;
	}

	/**
	 * Check if IP is whitelisted during lockdown.
	 *
	 * @param string $ip IP address.
	 * @return bool
	 */
	private function is_ip_whitelisted( $ip ) {
		$lockdown = self::get_lockdown_data();

		if ( ! $lockdown || empty( $lockdown->whitelist_ips ) ) {
			return false;
		}

		$whitelist = explode( "\n", $lockdown->whitelist_ips );
		$whitelist = array_map( 'trim', $whitelist );

		return in_array( $ip, $whitelist, true ) || in_array( '*', $whitelist, true );
	}

	/**
	 * Activate lockdown mode.
	 *
	 * @param int    $user_id User ID who activated lockdown.
	 * @param string $reason  Reason for lockdown.
	 * @param array  $whitelist_ips IPs to whitelist.
	 * @return bool
	 */
	public static function activate( $user_id = 0, $reason = '', $whitelist_ips = array() ) {
		global $wpdb;

		$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prefix . 'zacls_lockdown',
			array(
				'is_active'     => 1,
				'activated_by'  => $user_id ? $user_id : get_current_user_id(),
				'activated_at'  => current_time( 'mysql' ),
				'reason'        => $reason ? $reason : esc_html__( 'Emergency lockdown activated by admin.', 'za-creative-login-shield' ),
				'whitelist_ips' => implode( "\n", $whitelist_ips ),
			),
			array( '%d', '%d', '%s', '%s', '%s' )
		);

		update_option( 'zacls_emergency_lockdown', 'yes' );
		wp_cache_delete( 'zacls_lockdown_data', 'zacls' );

		return true;
	}

	/**
	 * Deactivate lockdown mode.
	 *
	 * @return bool
	 */
	public static function deactivate() {
		global $wpdb;

		$wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prefix . 'zacls_lockdown',
			array(
				'is_active'      => 0,
				'deactivated_at' => current_time( 'mysql' ),
			),
			array( 'is_active' => 1 ),
			array( '%d', '%s' ),
			array( '%d' )
		);

		update_option( 'zacls_emergency_lockdown', 'no' );
		wp_cache_delete( 'zacls_lockdown_data', 'zacls' );

		return true;
	}

	/**
	 * Show admin notice when lockdown is active.
	 */
	public function show_lockdown_notice() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( ! $this->is_lockdown_active() ) {
			return;
		}

		$deactivate_url = wp_nonce_url(
			add_query_arg( 'zacls_action', 'deactivate_lockdown' ),
			'zacls_lockdown_action'
		);

		printf(
			'<div class="notice notice-error is-dismissible"><p><strong>%s</strong> %s <a href="%s" class="button button-primary">%s</a></p></div>',
			esc_html__( 'EMERGENCY LOCKDOWN ACTIVE:', 'za-creative-login-shield' ),
			esc_html__( 'All login attempts are blocked except whitelisted IPs.', 'za-creative-login-shield' ),
			esc_url( $deactivate_url ),
			esc_html__( 'Deactivate Lockdown', 'za-creative-login-shield' )
		);
	}
}
