<?php

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

class BSPP_Magic_Login {
    private $repo;

    /** @var bool Whether [bspp_magic_login] ran on this request (used to avoid duplicating Manage subscription in the footer). */
    private static $shortcode_used_this_request = false;

    public static function shortcode_used_this_request() {
        return self::$shortcode_used_this_request;
    }

    public function __construct() {
        $this->repo = new BSPP_Magic_Link_Repository();
        $this->register_hooks();
    }

    private function register_hooks() {
        add_action('admin_post_bspp_magic_login_request', [$this, 'handle_request']);
        add_action('admin_post_nopriv_bspp_magic_login_request', [$this, 'handle_request']);
        add_action('admin_post_bspp_magic_login_verify', [$this, 'handle_verify']);
        add_action('admin_post_nopriv_bspp_magic_login_verify', [$this, 'handle_verify']);
        add_shortcode('bspp_magic_login', [$this, 'render_shortcode']);
    }

    public function render_shortcode() {
        self::$shortcode_used_this_request = true;

        $message = '';
        $state = isset($_GET['bspp_magic']) ? sanitize_key(wp_unslash($_GET['bspp_magic'])) : '';
        if ($state === 'sent') {
            $message = 'Check your email for the magic login link.';
        } elseif ($state === 'invalid') {
            $message = 'That login link is invalid or expired.';
        } elseif ($state === 'rate_limited') {
            $message = 'Please wait a minute before requesting another login link.';
        } elseif ($state === 'mail_failed') {
            $message = 'We could not send email from this environment. Please verify local mail setup.';
        }

        $action_url = admin_url('admin-post.php');
        $redirect_to = is_singular()
            ? add_query_arg('bspp_magic_login', '1', get_permalink())
            : add_query_arg('bspp_magic_login', '1', home_url('/'));

        ob_start();
        ?>
        <div style="border:1px solid #ddd; padding:16px; margin:16px 0;">
            <h3 style="margin-top:0;">Log in with magic link</h3>
            <?php if (!empty($message)) : ?>
                <p><?php echo esc_html($message); ?></p>
            <?php endif; ?>
            <form method="post" action="<?php echo esc_url($action_url); ?>">
                <input type="hidden" name="action" value="bspp_magic_login_request" />
                <input type="hidden" name="redirect_to" value="<?php echo esc_url($redirect_to); ?>" />
                <?php wp_nonce_field('bspp_magic_login_request', 'bspp_magic_login_nonce'); ?>
                <label for="bspp_magic_login_email">Email</label>
                <input id="bspp_magic_login_email" type="email" name="email" required style="margin:0 8px;" />
                <button type="submit">Send magic link</button>
            </form>
        </div>
        <?php
        $html = ob_get_clean();

        if (is_user_logged_in()) {
            $portal_url = BSPP_Plugin::get_manage_subscription_portal_url_for_user();
            if ($portal_url !== '') {
                $html .= '<p class="bspp-manage-subscription"><a href="' . esc_url($portal_url) . '">' . esc_html__('Manage subscription', 'bobasoftware-publisher-paywall') . '</a></p>';
            }
        }

        return $html;
    }

    public function handle_request() {
        if (!isset($_REQUEST['bspp_magic_login_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['bspp_magic_login_nonce'])), 'bspp_magic_login_request')) {
            wp_die('Invalid request');
        }

        $email = isset($_REQUEST['email']) ? sanitize_email(wp_unslash($_REQUEST['email'])) : '';
        if (!is_email($email)) {
            wp_die('Invalid email');
        }

        $redirect_to = isset($_REQUEST['redirect_to']) ? esc_url_raw(wp_unslash($_REQUEST['redirect_to'])) : home_url('/');
        $redirect_to = wp_validate_redirect($redirect_to, home_url('/'));

        // Preserve email through redirects so the UI can resend without requiring user re-entry.
        $redirect_to = add_query_arg('bspp_magic_email', $email, $redirect_to);

        // Basic rate limiting by email hash (1 request/minute).
        $rate_key = 'bobasoftware_pp_magic_rate_' . md5(strtolower($email));
        if (get_transient($rate_key)) {
            wp_safe_redirect(add_query_arg('bspp_magic', 'rate_limited', $redirect_to));
            exit;
        }
        set_transient($rate_key, 1, MINUTE_IN_SECONDS);

        $user = get_user_by('email', $email);
        if (!$user) {
            $username = sanitize_user(current(explode('@', $email)), true);
            if (username_exists($username)) {
                $username .= '_' . wp_generate_password(4, false, false);
            }
            $user_id = wp_create_user($username, wp_generate_password(24, true, true), $email);
            if (is_wp_error($user_id)) {
                wp_die('Could not create account.');
            }
            $user = get_user_by('id', $user_id);
        }

        if (!$user || empty($user->ID)) {
            wp_die('Could not create login link.');
        }

        $raw_token = wp_generate_password(40, false, false);
        $token_hash = wp_hash($raw_token, 'nonce');
        $expires_at = gmdate('Y-m-d H:i:s', time() + (15 * MINUTE_IN_SECONDS));
        $created = $this->repo->create((int) $user->ID, $token_hash, $expires_at);
        if (!$created) {
            wp_die('Could not create login token.');
        }

        $verify_url = add_query_arg(
            [
                'action' => 'bspp_magic_login_verify',
                'token' => rawurlencode($raw_token),
                'redirect_to' => rawurlencode($redirect_to),
            ],
            admin_url('admin-post.php')
        );

        $subject = 'Your magic login link';
        $body = "Use this link to log in:\n\n" . esc_url_raw($verify_url) . "\n\nThis link expires in 15 minutes.";
        $mail_sent = wp_mail($email, $subject, $body);
        if (!$mail_sent) {
            wp_safe_redirect(add_query_arg('bspp_magic', 'mail_failed', $redirect_to));
            exit;
        }

        wp_safe_redirect(add_query_arg('bspp_magic', 'sent', $redirect_to));
        exit;
    }

    /**
     * Email a magic login link after subscription checkout when the buyer was not logged in to WordPress.
     * Redirect target: the subscribed-from post (if published) with bspp_magic_login=1, else site home.
     *
     * @param int $user_id Target WordPress user.
     * @param int $post_id Post ID from checkout metadata (0 uses homepage).
     * @return bool True if wp_mail reported success.
     */
    public static function send_post_subscription_welcome_magic_link($user_id, $post_id) {
        $user_id = (int) $user_id;
        if ($user_id <= 0) {
            return false;
        }
        $user = get_user_by('id', $user_id);
        if (!$user || !is_email((string) $user->user_email)) {
            return false;
        }
        $email = (string) $user->user_email;

        $post_id = (int) $post_id;
        $post = $post_id > 0 ? get_post($post_id) : null;
        if ($post && $post->post_type === 'post' && $post->post_status === 'publish') {
            $redirect_base = add_query_arg('bspp_magic_login', '1', get_permalink($post_id));
        } else {
            $redirect_base = add_query_arg('bspp_magic_login', '1', home_url('/'));
        }
        $redirect_to = wp_validate_redirect(esc_url_raw($redirect_base), home_url('/'));

        $repo = new BSPP_Magic_Link_Repository();
        $raw_token = wp_generate_password(40, false, false);
        $token_hash = wp_hash($raw_token, 'nonce');
        $expires_at = gmdate('Y-m-d H:i:s', time() + (15 * MINUTE_IN_SECONDS));
        if (!$repo->create($user_id, $token_hash, $expires_at)) {
            return false;
        }

        $verify_url = add_query_arg(
            [
                'action' => 'bspp_magic_login_verify',
                'token' => rawurlencode($raw_token),
                'redirect_to' => rawurlencode($redirect_to),
            ],
            admin_url('admin-post.php')
        );

        $site = wp_specialchars_decode((string) get_bloginfo('name'), ENT_QUOTES);
        if ($site === '') {
            $host = wp_parse_url(home_url('/'), PHP_URL_HOST);
            $site = is_string($host) && $host !== '' ? $host : 'WordPress';
        }

        $subject = sprintf(
            /* translators: %s: site name */
            __('Welcome to %s — click to access your account', 'bobasoftware-publisher-paywall'),
            $site
        );

        $body = sprintf(
            /* translators: 1: magic login URL, 2: site name */
            __("Thanks for subscribing — your membership is active.\n\nOpen this link on any device to sign in and keep reading:\n\n%1\$s\n\nThis link expires in 15 minutes.\n\n— %2\$s", 'bobasoftware-publisher-paywall'),
            $verify_url,
            $site
        );

        return (bool) wp_mail($email, $subject, $body);
    }

    public function handle_verify() {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- not a form submission, magic login verify URL parameters.
        $raw_token = isset($_REQUEST['token']) ? sanitize_text_field(wp_unslash($_REQUEST['token'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- not a form submission, magic login verify URL parameters.
        $redirect_to = isset($_REQUEST['redirect_to']) ? esc_url_raw(wp_unslash($_REQUEST['redirect_to'])) : home_url('/');
        $redirect_to = wp_validate_redirect($redirect_to, home_url('/'));

        if (empty($raw_token)) {
            wp_safe_redirect(add_query_arg('bspp_magic', 'invalid', $redirect_to));
            exit;
        }

        $token_hash = wp_hash($raw_token, 'nonce');
        $row = $this->repo->get_valid_by_hash($token_hash);
        if (!$row || empty($row->user_id)) {
            wp_safe_redirect(add_query_arg('bspp_magic', 'invalid', $redirect_to));
            exit;
        }

        $this->repo->mark_used((int) $row->id);

        $user = get_user_by('id', (int) $row->user_id);
        if (!$user) {
            wp_safe_redirect(add_query_arg('bspp_magic', 'invalid', $redirect_to));
            exit;
        }

        wp_set_current_user((int) $user->ID);
        wp_set_auth_cookie((int) $user->ID, true);
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WP hook.
        do_action('wp_login', $user->user_login, $user);

        wp_safe_redirect($redirect_to);
        exit;
    }
}

