<?php
/**
 * Custom Login URL handler.
 *
 * @package LoginPageCustomizerAndDesigner
 */

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

/**
 * Class LPCD_Url_Changer
 *
 * Handles changing the login URL slug and redirecting the old wp-login.php.
 */
class LPCD_Url_Changer {

	/**
	 * Whether we are currently performing a redirect (prevents filter loops).
	 *
	 * @var bool
	 */
	private static $is_redirecting = false;

	/**
	 * Constructor.
	 */
	public function __construct() {
		// Registration redirect is independent of the custom login URL feature.
		add_filter( 'registration_redirect', array( $this, 'registration_redirect' ) );

		// If the entire plugin is disabled, skip all custom login URL logic.
		if ( ! LPCD_Settings_Manager::get( 'pluginEnabled', true ) ) {
			return;
		}

		if ( ! LPCD_Settings_Manager::get( 'enableCustomLogin', false ) ) {
			return;
		}

		$slug = sanitize_title( LPCD_Settings_Manager::get( 'customLoginSlug', '' ) );
		if ( empty( $slug ) ) {
			return;
		}

		// Block wp-admin and canonical /login redirects for logged-out users.
		add_action( 'init', array( $this, 'block_wp_admin_and_canonical' ), 0 );

		// Handle custom slug → load wp-login.php.
		add_action( 'wp_loaded', array( $this, 'handle_custom_slug' ), 0 );

		// Replace wp-login.php in generated URLs.
		add_filter( 'site_url', array( $this, 'filter_login_url' ), 10, 4 );
		add_filter( 'network_site_url', array( $this, 'filter_login_url' ), 10, 3 );
		add_filter( 'wp_redirect', array( $this, 'filter_redirect' ), 10, 1 );
		add_filter( 'register_url', array( $this, 'filter_redirect' ) );

		// Block default wp-login.php — run IMMEDIATELY during constructor.
		// This works because the constructor runs during plugins_loaded,
		// and $pagenow is already set by wp-includes/vars.php at this point.
		$this->maybe_block_default_login();
	}

	/**
	 * Block direct access to wp-login.php immediately.
	 *
	 * Called from the constructor during plugins_loaded.
	 * Uses raw PHP header() to guarantee the redirect works.
	 */
	private function maybe_block_default_login() {
		global $pagenow;

		// Only block if we are on wp-login.php.
		if ( 'wp-login.php' !== $pagenow ) {
			return;
		}

		// Allow POST requests (form submissions: login, register, lost password, etc.).
		if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) {
			return;
		}

		// Allow specific actions.
		$allowed_actions = array( 'logout', 'postpass', 'rp', 'resetpass', 'confirmaction', 'lostpassword', 'retrievepassword', 'register' );
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$current_action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : '';
		if ( in_array( $current_action, $allowed_actions, true ) ) {
			return;
		}

		// Allow special query params.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['checkemail'] ) || isset( $_GET['loggedout'] ) || isset( $_GET['registration'] ) || isset( $_GET['interim-login'] ) ) {
			return;
		}

		// Perform redirect based on settings.
		$this->do_default_login_redirect();
	}

	/**
	 * Block /wp-admin/ and canonical /login for logged-out users.
	 *
	 * This prevents auth_redirect() from redirecting unauthorized users
	 * to the secret custom login URL, which would reveal it.
	 */
	public function block_wp_admin_and_canonical() {
		// 1. Stop WordPress from redirecting /login to the custom login URL.
		remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );

		// 2. Block backend and alias access for logged-out users.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
		$path        = untrailingslashit( wp_parse_url( $request_uri, PHP_URL_PATH ) );

		if ( ! empty( $path ) ) {
			$is_backend     = false !== strpos( $path, '/wp-admin' );
			$is_login_alias = in_array( $path, array( '/login', '/admin', '/dashboard' ), true );

			if ( $is_backend || $is_login_alias ) {
				// Allow ajax and post.
				if ( false === strpos( $path, '/admin-ajax.php' ) && false === strpos( $path, '/admin-post.php' ) ) {
					// If not logged in, they shouldn't be here. Send them away.
					if ( ! is_user_logged_in() ) {
						$this->do_default_login_redirect();
					}
				}
			}
		}
	}

	/**
	 * Perform the default login redirect based on user settings.
	 */
	private function do_default_login_redirect() {
		$redirect_type = LPCD_Settings_Manager::get( 'defaultLoginRedirectType', '404' );

		if ( 'homepage' === $redirect_type ) {
			header( 'Location: ' . home_url( '/' ), true, 302 );
			exit;
		}

		if ( 'custom' === $redirect_type ) {
			$url = LPCD_Settings_Manager::get( 'defaultLoginRedirectUrl', '' );
			if ( ! empty( $url ) ) {
				header( 'Location: ' . esc_url_raw( $url ), true, 302 );
				exit;
			}
		}

		// Default: 404.
		status_header( 404 );
		nocache_headers();
		wp_die(
			esc_html__( 'Page not found.', 'login-page-customizer-and-designer' ),
			esc_html__( '404 Not Found', 'login-page-customizer-and-designer' ),
			array( 'response' => 404 )
		);
	}

	/**
	 * Handle requests to the custom login slug → load wp-login.php.
	 */
	public function handle_custom_slug() {
		$slug = sanitize_title( LPCD_Settings_Manager::get( 'customLoginSlug', '' ) );
		if ( empty( $slug ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
		$parsed      = wp_parse_url( $request_uri );
		$path        = isset( $parsed['path'] ) ? untrailingslashit( $parsed['path'] ) : '';

		$custom_login_path = untrailingslashit( wp_parse_url( home_url( '/' . $slug ), PHP_URL_PATH ) );

		if ( $path === $custom_login_path || $path === $custom_login_path . '/' ) {
			// Expose necessary variables to global scope (wp-login.php expects them).
			global $pagenow, $error, $user_login, $action, $interim_login;

			$pagenow    = 'wp-login.php'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
			$error      = '';
			$user_login = '';

			require_once ABSPATH . 'wp-login.php';
			exit;
		}
	}

	/**
	 * Replace wp-login.php in URLs generated by site_url / network_site_url.
	 *
	 * @param string      $url     The complete site URL.
	 * @param string      $path    Path relative to the site URL.
	 * @param string|null $scheme  URL scheme.
	 * @param int|null    $blog_id Blog ID.
	 * @return string Modified URL.
	 */
	public function filter_login_url( $url, $path, $scheme = null, $blog_id = null ) {
		if ( self::$is_redirecting ) {
			return $url;
		}

		$slug = sanitize_title( LPCD_Settings_Manager::get( 'customLoginSlug', '' ) );
		if ( empty( $slug ) ) {
			return $url;
		}

		if ( $path === 'wp-login.php' || false !== strpos( $path, 'wp-login.php' ) ) {
			$url = str_replace( 'wp-login.php', $slug, $url );
		}

		return $url;
	}

	/**
	 * Filter redirect URLs and register URL to replace wp-login.php.
	 *
	 * @param string $location URL.
	 * @return string Modified URL.
	 */
	public function filter_redirect( $location ) {
		if ( self::$is_redirecting ) {
			return $location;
		}

		$slug = sanitize_title( LPCD_Settings_Manager::get( 'customLoginSlug', '' ) );
		if ( empty( $slug ) ) {
			return $location;
		}

		if ( false !== strpos( $location, 'wp-login.php' ) ) {
			return str_replace( 'wp-login.php', $slug, $location );
		}

		return $location;
	}

	/**
	 * Handle registration redirect.
	 *
	 * @param string $redirect_to Default redirect URL.
	 * @return string Modified redirect URL.
	 */
	public function registration_redirect( $redirect_to ) {
		$type = LPCD_Settings_Manager::get( 'registrationRedirectType', 'default' );

		switch ( $type ) {
			case 'homepage':
				return home_url( '/' );
			case 'custom':
				$url = LPCD_Settings_Manager::get( 'registrationRedirectUrl', '' );
				return ! empty( $url ) ? esc_url( $url ) : $redirect_to;
			default:
				return $redirect_to;
		}
	}
}
