<?php

defined( 'ABSPATH' ) || exit;

/**
 * Login Redirects module.
 *
 * Per-role landing-page redirect after a successful login. WordPress's default
 * is `wp-admin/` (or whatever was in `?redirect_to=` on the login URL) for
 * every role, which is not always where lower-privilege users should land —
 * editors are more useful in `edit.php`, WooCommerce customers in
 * `/my-account/`, subscribers on the home page, etc.
 *
 * Hooks `login_redirect` (priority 20, 3 args). When the user has a role
 * with a configured redirect, this module returns that URL. Multi-role users
 * are handled by iterating the user's roles array in stored order and picking
 * the first role that has a non-empty configured target.
 *
 * URL resolution:
 *  - Empty string → return WP's incoming redirect URL unchanged (default behaviour).
 *  - Starts with `/` → resolved against `home_url()` (`/my-account` → site URL).
 *  - Starts with `http://` or `https://` → passed through verbatim. WordPress
 *    pipes the filter result through `wp_safe_redirect()`, so external hosts
 *    that aren't in `allowed_redirect_hosts` are already blocked by core.
 *  - Anything else → treated as a relative path under `home_url()`.
 *
 * No special handling for super admin / network admin — single-site only.
 *
 * @package BW_Dev
 */

class BW_Dev_Module_Login_Redirect implements BW_Dev_Module_Interface {

	public function slug(): string {
		return 'login_redirect';
	}

	public function label(): string {
		return __( 'Login Redirects', 'bw-dev' );
	}

	public function group(): string {
		return 'security';
	}

	public function default_settings(): array {
		return array(
			'roles' => array(),
		);
	}

	public function sanitize( array $data ): array {
		$roles_raw = isset( $data['roles'] ) && is_array( $data['roles'] ) ? $data['roles'] : array();
		$roles     = array();

		foreach ( $roles_raw as $role_slug => $url ) {
			$role_slug = sanitize_key( (string) $role_slug );
			if ( '' === $role_slug ) {
				continue;
			}
			$url = (string) $url;
			// Strip control chars + cap length.
			$url                 = preg_replace( '/[\x00-\x1f\x7f]/', '', $url );
			$url                 = trim( substr( (string) $url, 0, 500 ) );
			$roles[ $role_slug ] = $url;
		}

		return array( 'roles' => $roles );
	}

	public function register(): void {
		add_filter( 'login_redirect', array( $this, 'filter_login_redirect' ), 20, 3 );
	}

	/**
	 * Apply the configured per-role redirect, if any.
	 *
	 * @param string           $redirect_to           URL WP is about to redirect to.
	 * @param string           $requested_redirect_to URL the request asked for (?redirect_to=).
	 * @param WP_User|WP_Error $user                  Authenticated user (or error on bad login).
	 */
	public function filter_login_redirect( $redirect_to, $requested_redirect_to, $user ) {
		unset( $requested_redirect_to );

		if ( ! ( $user instanceof WP_User ) ) {
			return $redirect_to;
		}

		$map = bw_dev()->settings()->get( $this->slug(), 'roles', array() );
		if ( ! is_array( $map ) || empty( $map ) ) {
			return $redirect_to;
		}

		$roles = (array) $user->roles;
		foreach ( $roles as $role ) {
			if ( ! isset( $map[ $role ] ) ) {
				continue;
			}
			$target = trim( (string) $map[ $role ] );
			if ( '' === $target ) {
				continue;
			}
			return $this->resolve_url( $target );
		}

		return $redirect_to;
	}

	/**
	 * Resolve a stored value (path or absolute URL) to a redirect target.
	 */
	private function resolve_url( string $value ): string {
		if ( 0 === strpos( $value, 'http://' ) || 0 === strpos( $value, 'https://' ) ) {
			return $value;
		}
		if ( 0 === strpos( $value, '/' ) ) {
			return home_url( $value );
		}
		return home_url( '/' . $value );
	}

	public function render_tab(): void {
		$map = bw_dev()->settings()->get( $this->slug(), 'roles', array() );
		if ( ! is_array( $map ) ) {
			$map = array();
		}

		$roles      = wp_roles()->roles;
		$field_base = BW_Dev_Settings::OPTION . '[' . $this->slug() . '][roles]';
		?>
		<p class="description">
			<?php esc_html_e( 'Send each user role to a specific URL after a successful login. Leave a field blank to keep WordPress\'s default behaviour for that role.', 'bw-dev' ); ?>
		</p>

		<table class="form-table" role="presentation">
			<tbody>
				<?php foreach ( $roles as $role_slug => $role_data ) : ?>
					<?php
					$role_label = isset( $role_data['name'] ) ? translate_user_role( (string) $role_data['name'] ) : (string) $role_slug;
					$current    = isset( $map[ $role_slug ] ) ? (string) $map[ $role_slug ] : '';
					$field_name = $field_base . '[' . $role_slug . ']';
					$field_id   = 'bw-dev-login-redirect-' . $role_slug;
					?>
					<tr>
						<th scope="row">
							<label for="<?php echo esc_attr( $field_id ); ?>">
								<?php echo esc_html( $role_label ); ?>
								<br /><code style="font-weight:normal;color:#646970;"><?php echo esc_html( $role_slug ); ?></code>
							</label>
						</th>
						<td>
							<input type="text" id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_name ); ?>" value="<?php echo esc_attr( $current ); ?>" class="regular-text code" placeholder="/wp-admin/edit.php" />
						</td>
					</tr>
				<?php endforeach; ?>
			</tbody>
		</table>

		<h3><?php esc_html_e( 'Quick templates', 'bw-dev' ); ?></h3>
		<p class="description">
			<?php esc_html_e( 'Copy any of these into a role\'s field above. Anything starting with `/` resolves against the site URL; anything starting with `http://` or `https://` passes through (external hosts are blocked by WordPress core).', 'bw-dev' ); ?>
		</p>
		<ul style="list-style:disc;margin-left:20px;">
			<li><code>/</code> — <?php esc_html_e( 'site home page', 'bw-dev' ); ?></li>
			<li><code>/wp-admin/</code> — <?php esc_html_e( 'WordPress dashboard (the default for everyone)', 'bw-dev' ); ?></li>
			<li><code>/wp-admin/edit.php</code> — <?php esc_html_e( 'Posts list (handy default for Editor + Author)', 'bw-dev' ); ?></li>
			<li><code>/wp-admin/edit.php?post_type=page</code> — <?php esc_html_e( 'Pages list', 'bw-dev' ); ?></li>
			<li><code>/wp-admin/profile.php</code> — <?php esc_html_e( 'profile page', 'bw-dev' ); ?></li>
			<li><code>/wp-admin/upload.php</code> — <?php esc_html_e( 'media library', 'bw-dev' ); ?></li>
			<li><code>/my-account/</code> — <?php esc_html_e( 'WooCommerce account page (typical Customer landing)', 'bw-dev' ); ?></li>
		</ul>

		<h3><?php esc_html_e( 'How role precedence works', 'bw-dev' ); ?></h3>
		<p>
			<?php esc_html_e( 'When a user has more than one role, this module walks the user\'s roles in the order WordPress stores them and uses the first role that has a non-empty redirect configured here. If none of the user\'s roles are configured, WordPress\'s default applies.', 'bw-dev' ); ?>
		</p>
		<?php
	}

	public function uninstall(): void {
		// Settings live under bw_dev_settings — root option drop covers them.
	}
}
