<?php
namespace BLR\Backline\Core;

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

final class ProfileHandler {
    private const PROFILE_ERROR_TRANSIENT_PREFIX = 'blr_ba_profile_error_';

    public static function boot(): void {
        add_action('admin_post_blr_ba_update_profile', [self::class, 'handle_legacy']);
        add_action('admin_post_blr_ba_update_profile_info', [self::class, 'handle_profile']);
        add_action('admin_post_blr_ba_update_password', [self::class, 'handle_password']);
    }

    private static function preflight(): array {
        if (!is_user_logged_in()) {
            wp_die(esc_html__('Forbidden', 'blr-backline'), 403);
        }

        if (!Access::user_can_access()) {
            wp_safe_redirect(Router::not_allowed_url());
            exit;
        }
        $nonce = isset($_POST['_wpnonce']) ? sanitize_text_field((string) wp_unslash($_POST['_wpnonce'])) : '';
        if ($nonce === '' || !wp_verify_nonce($nonce, 'blr_ba_update_profile')) {
            wp_die(esc_html__('Security check failed.', 'blr-backline'));
        }

        $uid = get_current_user_id();
        $slug = SettingsPage::get_dashboard_slug();
        $redir = home_url('/' . $slug . '/profile/');

        return [(int) $uid, (string) $redir];
    }


    private static function error_transient_key(int $user_id): string {
        return self::PROFILE_ERROR_TRANSIENT_PREFIX . absint($user_id);
    }

    private static function set_profile_error(int $user_id, string $message): void {
        $message = trim($message);
        if ($user_id <= 0 || $message == '') {
            return;
        }

        set_transient(self::error_transient_key($user_id), $message, MINUTE_IN_SECONDS * 5);
    }

    public static function consume_profile_error(?int $user_id = null): string {
        $user_id = $user_id ?? get_current_user_id();
        if ($user_id <= 0) {
            return '';
        }

        $key = self::error_transient_key($user_id);
        $message = get_transient($key);
        delete_transient($key);

        return is_string($message) ? $message : '';
    }

    private static function redirect_with_error(int $user_id, string $redirect_url, string $message): void {
        self::set_profile_error($user_id, $message);
        wp_safe_redirect($redirect_url);
        exit;
    }

    public static function handle_legacy(): void {
        // Legacy routing hint only. The delegated handlers call preflight(), which verifies the nonce before any state change.
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Safe routing hint; nonce verification happens in the target handler.
        $mode = sanitize_key((string) wp_unslash($_POST['mode'] ?? 'profile'));
        if ($mode === 'password') {
            self::handle_password();
            return;
        }

        self::handle_profile();
    }

    public static function handle_password(): void {
        [$uid, $redir] = self::preflight();

        // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verified in preflight(); password values must remain raw for verification and hashing.
        $current = isset($_POST['current_password']) ? (string) wp_unslash($_POST['current_password']) : '';
        $new = isset($_POST['new_password']) ? (string) wp_unslash($_POST['new_password']) : '';
        $confirm = isset($_POST['confirm_password']) ? (string) wp_unslash($_POST['confirm_password']) : '';
        // phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

        if ($new === '' && $confirm === '') {
            self::redirect_with_error($uid, $redir, __('Enter a new password.', 'blr-backline'));
        }

        if ($new !== $confirm) {
            self::redirect_with_error($uid, $redir, __('New passwords do not match.', 'blr-backline'));
        }

        if (strlen($new) < 8) {
            self::redirect_with_error($uid, $redir, __('Password must be at least 8 characters.', 'blr-backline'));
        }

        $user = get_user_by('id', $uid);
        if (!$user || !wp_check_password($current, $user->user_pass, $uid)) {
            self::redirect_with_error($uid, $redir, __('Current password is incorrect.', 'blr-backline'));
        }

        $remember = self::current_session_is_persistent();

        wp_set_password($new, $uid);

        // Invalidate any previously issued auth tokens for this user before creating the fresh current session.
        // This prevents old browser/device sessions from surviving a password change.
        \WP_Session_Tokens::get_instance($uid)->destroy_all();

        wp_set_current_user($uid);
        wp_set_auth_cookie($uid, $remember);

        wp_safe_redirect(add_query_arg(['updated' => '1'], $redir));
        exit;
    }


    private static function current_session_is_persistent(): bool {
        $cookie = wp_parse_auth_cookie('', 'logged_in');
        if (!is_array($cookie)) {
            return false;
        }

        $expiration = isset($cookie['expiration']) ? (int) $cookie['expiration'] : 0;
        if ($expiration <= 0) {
            return false;
        }

        return $expiration > (time() + (2 * DAY_IN_SECONDS));
    }

    public static function handle_profile(): void {
        [$uid, $redir] = self::preflight();

        // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified in preflight().
        $display = sanitize_text_field((string) wp_unslash($_POST['display_name'] ?? ''));
        $email   = sanitize_email((string) wp_unslash($_POST['user_email'] ?? ''));
        $url     = esc_url_raw((string) wp_unslash($_POST['user_url'] ?? ''));
        // phpcs:enable WordPress.Security.NonceVerification.Missing

        $update = [
            'ID' => $uid,
            'display_name' => $display,
            'user_email' => $email,
            'user_url' => $url,
        ];

        $res = wp_update_user($update);

        if (is_wp_error($res)) {
            self::redirect_with_error($uid, $redir, $res->get_error_message());
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in preflight().
        $remove = !empty($_POST['remove_avatar']);
        $previous_avatar_id = absint(get_user_meta($uid, 'blr_ba_avatar_id', true));
        if ($remove) {
            delete_user_meta($uid, 'blr_ba_avatar_id');
            if ($previous_avatar_id > 0) {
                CrudHelpers::delete_attachment($previous_avatar_id);
            }
        } else {
            $upload = CrudHelpers::handle_upload('avatar_image', 0, CrudHelpers::image_mimes());
            if ($upload && !empty($upload['attachment_id'])) {
                $aid = (int) $upload['attachment_id'];
                if (wp_attachment_is_image($aid)) {
                    update_user_meta($uid, 'blr_ba_avatar_id', $aid);
                    if ($previous_avatar_id > 0 && $previous_avatar_id !== $aid) {
                        CrudHelpers::delete_attachment($previous_avatar_id);
                    }
                } else {
                    CrudHelpers::cleanup_upload_result($upload);
                    self::redirect_with_error($uid, $redir, __('The uploaded avatar must be a supported image file.', 'blr-backline'));
                }
            } elseif (CrudHelpers::has_selected_uploads('avatar_image')) {
                $upload_errors = CrudHelpers::get_last_upload_errors();
                $upload_error = isset($upload_errors[0]) ? (string) $upload_errors[0] : __('The avatar upload failed.', 'blr-backline');
                self::redirect_with_error($uid, $redir, $upload_error);
            }
        }

        wp_safe_redirect(add_query_arg(['updated' => '1'], $redir));
        exit;
    }
}
