<?php
if (!defined('ABSPATH')) exit;

/**
 * Login/logout redirect handling for Custom Auth Suite™.
 */

if (!function_exists('custausu_login_redirects_request_value')) {
  function custausu_login_redirects_request_value(string $key, string $default = ''): string {
    $key = sanitize_key($key);

    if ($key === '') {
      return $default;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only login redirect helper; action handlers validate the relevant flow separately.
    if (!isset($_REQUEST[$key])) {
      return $default;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Value is unslashed and normalized immediately below; redirect URLs are URL-sanitized by key.
    $value = wp_unslash($_REQUEST[$key]);

    if (is_array($value)) {
      return $default;
    }

    $value = trim((string) $value);

    if (in_array($key, ['redirect_to', 'requested_redirect_to'], true)) {
      return esc_url_raw($value);
    }

    return sanitize_text_field($value);
  }
}

if (!function_exists('custausu_login_redirects_post_value')) {
  function custausu_login_redirects_post_value(string $key, string $default = ''): string {
    $key = sanitize_key($key);

    if ($key === '') {
      return $default;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Public WordPress login POST does not carry a CAS nonce; this helper only reads and normalizes values.
    if (!isset($_POST[$key])) {
      return $default;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Public WordPress login POST value is unslashed and normalized immediately below.
    $value = wp_unslash($_POST[$key]);

    if (is_array($value)) {
      return $default;
    }

    $value = trim((string) $value);

    if (in_array($key, ['redirect_to', 'requested_redirect_to'], true)) {
      return esc_url_raw($value);
    }

    return sanitize_text_field($value);
  }
}

if (!function_exists('custausu_login_redirects_server_value')) {
  function custausu_login_redirects_server_value(string $key, string $default = ''): string {
    $key = strtoupper((string) preg_replace('/[^A-Z0-9_]/i', '', $key));

    if ($key === '') {
      return $default;
    }

    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Server value is read-only request metadata and is unslashed/sanitized immediately below.
    if (!isset($_SERVER[$key])) {
      return $default;
    }

    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Server value is normalized based on the specific metadata key.
    $value = wp_unslash($_SERVER[$key]);

    if (is_array($value)) {
      return $default;
    }

    $value = trim((string) $value);

    if ($key === 'REQUEST_METHOD') {
      return strtoupper(sanitize_key($value));
    }

    if (in_array($key, ['REQUEST_URI', 'HTTP_REFERER'], true)) {
      return esc_url_raw($value);
    }

    return sanitize_text_field($value);
  }
}

if (!function_exists('custausu_login_redirects_url_path')) {
  function custausu_login_redirects_url_path(string $url): string {
    $path = (string) wp_parse_url($url, PHP_URL_PATH);

    if ($path === '') {
      return '';
    }

    return '/' . trim($path, '/');
  }
}

if (!function_exists('custausu_login_redirects_log')) {
  function custausu_login_redirects_log(string $channel, string $message, array $context = [], string $level = 'debug'): void {
    if (!function_exists('custausu_log')) {
      return;
    }

    $safe = [];

    foreach ($context as $key => $value) {
      if (is_string($value) && in_array($key, ['redirect_to', 'requested_redirect_to', 'final_redirect_to', 'referer', 'dest', 'uri', 'ref'], true)) {
        $safe[$key . '_path'] = custausu_login_redirects_url_path($value);
        continue;
      }

      if (is_string($value) && in_array($key, ['username', 'user', 'user_login'], true)) {
        $safe[$key . '_hash'] = substr(hash('sha256', strtolower($value)), 0, 12);
        continue;
      }

      $safe[$key] = $value;
    }

    custausu_log($channel, $message, $safe, $level);
  }
}

if (!function_exists('custausu_detect_lang_for_logout_redirect')) {
  function custausu_detect_lang_for_logout_redirect(string $requested = '', string $referer = ''): string {
    unset($requested, $referer);

    return custausu_default_route_language();
  }
}

if (!function_exists('custausu_logout_home_path_for_lang')) {
  function custausu_logout_home_path_for_lang(string $lang): string {
    unset($lang);

    return '/';
  }
}

if (!function_exists('custausu_get_logout_redirect_path')) {
  function custausu_get_logout_redirect_path(string $lang): string {
    unset($lang);
    $lang = custausu_default_route_language();
    $path = function_exists('custausu_config') ? (string) custausu_config("routes.logout_redirect.$lang", '') : '';

    if ($path === '') {
      return custausu_logout_home_path_for_lang($lang);
    }

    return '/' . trim($path, '/') . '/';
  }
}

if (!function_exists('custausu_login_ref_matches_configured_route')) {
  function custausu_login_ref_matches_configured_route(string $url): bool {
    $url = trim($url);

    if ($url === '' || !function_exists('custausu_route_url')) {
      return false;
    }

    $ref_path = custausu_login_redirects_url_path($url);

    if ($ref_path === '') {
      return false;
    }

    $lang = custausu_default_route_language();
    $login_url = (string) custausu_route_url('login', $lang);
    $login_path = custausu_login_redirects_url_path($login_url);

    return $login_path !== '' && $ref_path === $login_path;
  }
}

if (!function_exists('custausu_login_request_is_from_custom_flow')) {
  function custausu_login_request_is_from_custom_flow(): bool {
    if (custausu_login_redirects_post_value('log') === '' || custausu_login_redirects_post_value('pwd') === '') {
      return false;
    }

    if (sanitize_key(custausu_login_redirects_post_value('custausu_login_flow')) === '1') {
      return true;
    }

    $referer = custausu_login_redirects_server_value('HTTP_REFERER');

    return function_exists('custausu_login_ref_matches_configured_route')
      && custausu_login_ref_matches_configured_route($referer);
  }
}

add_filter('logout_redirect', function($redirect_to, $requested_redirect_to, $user) {
  if (function_exists('custausu_safe_mode_is_enabled') && custausu_safe_mode_is_enabled()) {
    return is_string($redirect_to) && $redirect_to !== '' ? $redirect_to : home_url('/');
  }

  $requested = is_string($requested_redirect_to) ? $requested_redirect_to : '';
  $referer = custausu_login_redirects_server_value('HTTP_REFERER');

  $lang = custausu_detect_lang_for_logout_redirect($requested, $referer);
  $path = custausu_get_logout_redirect_path($lang);
  $dest = home_url($path);

  custausu_login_redirects_log('redirect', 'logout redirect resolved', [
    'requested_redirect_to' => $requested,
    'referer' => $referer,
    'lang' => $lang,
    'path' => $path,
    'dest' => $dest,
  ], 'debug');

  return $dest;
}, 10, 3);

add_filter('login_redirect', function($redirect_to, $requested_redirect_to, $user) {
  if (!($user instanceof WP_User)) {
    return $redirect_to;
  }

  $requested = is_string($requested_redirect_to) ? trim($requested_redirect_to) : '';
  $final = is_string($redirect_to) ? trim($redirect_to) : '';

  $lang = custausu_default_route_language();

  custausu_login_redirects_log('redirect', 'post-login redirect resolved', [
    'user_id' => (int) $user->ID,
    'requested_redirect_to' => $requested,
    'final_redirect_to' => $final,
    'lang' => $lang,
  ], 'info');

  return $redirect_to;
}, 20, 3);

add_action('wp_login', function($user_login, $user) {
  $redirect_to = function_exists('custausu_extract_redirect_to_from_request')
    ? (string) custausu_extract_redirect_to_from_request()
    : custausu_login_redirects_request_value('redirect_to');

  $lang = custausu_default_route_language();

  custausu_login_redirects_log('login', 'wp_login success', [
    'user_id' => ($user instanceof WP_User) ? (int) $user->ID : 0,
    'user_login' => (string) $user_login,
    'redirect_to' => $redirect_to,
    'lang' => $lang,
    'uri' => custausu_login_redirects_server_value('REQUEST_URI'),
  ], 'debug');
}, 10, 2);

add_filter('authenticate', function($user, $username, $password) {
  if (function_exists('custausu_safe_mode_is_enabled') && custausu_safe_mode_is_enabled()) {
    return $user;
  }

  if (custausu_login_redirects_server_value('REQUEST_METHOD') !== 'POST') {
    return $user;
  }

  $from_custom_flow = function_exists('custausu_login_request_is_from_custom_flow')
    ? custausu_login_request_is_from_custom_flow()
    : false;

  if (!$from_custom_flow) {
    return $user;
  }


  custausu_login_redirects_log('login', 'login request passed security checks', [
    'user' => (string) $username,
    'uri' => custausu_login_redirects_server_value('REQUEST_URI'),
    'has_redirect_to' => custausu_login_redirects_post_value('redirect_to') !== '',
  ], 'debug');

  return $user;
}, 5, 3);

if (!function_exists('custausu_redirect_failed_login_to_custom_login')) {
  function custausu_redirect_failed_login_to_custom_login(string $username, array $error_codes = []): void {
    if (function_exists('custausu_safe_mode_is_enabled') && custausu_safe_mode_is_enabled()) {
      return;
    }

    $from_custom_flow = function_exists('custausu_login_request_is_from_custom_flow')
      ? custausu_login_request_is_from_custom_flow()
      : false;

    if (!$from_custom_flow) {
      custausu_login_redirects_log('login', 'login failure ignored outside CAS flow', [
        'username' => $username,
        'uri' => custausu_login_redirects_server_value('REQUEST_URI'),
      ], 'debug');

      return;
    }

    $redirect_to = function_exists('custausu_extract_redirect_to_from_request')
      ? (string) custausu_extract_redirect_to_from_request()
      : custausu_login_redirects_request_value('redirect_to');

    $lang = custausu_default_route_language();

    $login_page = function_exists(
      'custausu_login_url_for_lang'
    )
      ? custausu_login_url_for_lang($lang)
      : '';


    if ($login_page === '' && function_exists('custausu_route_url')) {
      $login_page = (string) custausu_route_url('login', $lang);
    }

    if ($login_page === '') {
      $login_page = wp_login_url();
    }

    $args = ['login' => 'failed'];

    if ($redirect_to !== '') {
      $args['redirect_to'] = $redirect_to;
    }

    $dest = add_query_arg($args, $login_page);

    custausu_login_redirects_log('login', 'login failure redirect to CAS login', [
      'username' => $username,
      'dest' => $dest,
      'redirect_to' => $redirect_to,
      'lang' => $lang,
      'errors' => $error_codes,
    ], 'info');

    wp_safe_redirect($dest);
    exit;
  }
}

add_action('wp_login_failed', function($username) {
  custausu_redirect_failed_login_to_custom_login((string) $username);
});

add_filter('authenticate', function($user, $username, $password) {
  if (!($user instanceof WP_Error)) {
    return $user;
  }

  custausu_redirect_failed_login_to_custom_login((string) $username, $user->get_error_codes());

  return $user;
}, 30, 3);


