<?php
/**
 * Delivery Error Admin Notice.
 *
 * @since 1.0.0 Added delivery error admin notices with hide_delivery_errors support.
 *
 * @package NimblyMail\SMTP
 */

namespace NimblyMail\SMTP\Alerts;

defined( 'ABSPATH' ) || exit;

use NimblyMail\SMTP\Options;
use WP_Error;

/**
 * Class DeliveryErrorNotice
 *
 * Stores recent mail failures in a transient and displays a dismissible
 * admin notice unless the hide_delivery_errors setting is enabled.
 *
 * @since 1.0.0 Added delivery error admin notices with hide_delivery_errors support.
 * @since 1.0.5 The admin notice now requires manage_options, since it exposed a
 *              recipient address and raw transport error to any logged-in user.
 */
class DeliveryErrorNotice {

    /**
     * Transient key for storing the last delivery error.
     *
     * @since 1.0.0
     *
     * @var string
     */
    private const TRANSIENT_KEY = 'nimblymail_last_delivery_error';

    /**
     * Transient TTL in seconds (15 minutes).
     *
     * @since 1.0.0
     *
     * @var int
     */
    private const TRANSIENT_TTL = 15 * MINUTE_IN_SECONDS;

    /**
     * Initialize hooks.
     *
     * Always hooks the failure listener so errors are captured regardless
     * of admin context. The admin notice hook only runs in the admin.
     *
     * @since 1.0.0 Added delivery error notice hooks.
     *
     * @return void
     */
    public function init(): void {
        add_action( 'nimblymail_mail_failed', array( $this, 'store_failure' ) );
        add_action( 'admin_notices', array( $this, 'maybe_show_notice' ) );
    }

    /**
     * Store a mail failure in a transient.
     *
     * @since 1.0.0 Added failure storage for admin notices.
     * @since 1.0.0 Suppress storage while the Developer Sandbox is active.
     *
     * @param WP_Error $error The WP_Error from wp_mail().
     *
     * @return void
     */
    public function store_failure( WP_Error $error ): void {
        if ( Options::init()->get( 'sandbox', 'enabled' ) ) {
            return;
        }

        $error_data = $error->get_error_data();

        $to = $error_data['to'] ?? 'Unknown';
        if ( is_array( $to ) ) {
            $to = implode( ', ', $to );
        }

        $data = array(
            'to'      => sanitize_text_field( $to ),
            'subject' => sanitize_text_field( $error_data['subject'] ?? 'Unknown' ),
            'error'   => sanitize_text_field( $error->get_error_message() ),
            'time'    => current_time( 'mysql' ),
        );

        set_transient( self::TRANSIENT_KEY, $data, self::TRANSIENT_TTL );
    }

    /**
     * Display a dismissible admin notice if a recent delivery error exists.
     *
     * Skips rendering when the hide_delivery_errors setting is enabled.
     *
     * @since 1.0.0 Added delivery error admin notice display.
     * @since 1.0.5 Restricted rendering to users who can manage the plugin's
     *              settings. admin_notices fires for anyone who can reach an
     *              admin page, so without this check any logged-in user
     *              (e.g. a subscriber on their own profile screen) could see
     *              another recipient's email address and the raw transport
     *              error — every other admin surface in this plugin already
     *              gates on manage_options.
     *
     * @return void
     */
    public function maybe_show_notice(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $error = get_transient( self::TRANSIENT_KEY );

        if ( empty( $error ) || ! is_array( $error ) ) {
            return;
        }

        if ( Options::init()->get( 'general', 'hide_delivery_errors' ) ) {
            return;
        }

        $logs_url = admin_url( 'admin.php?page=nimblymail-smtp#/logs' );

        echo '<div class="notice notice-error is-dismissible">';
        echo '<p>';
        echo '<strong>' . esc_html__( 'NimblyMail:', 'nimblymail-smtp' ) . '</strong> ';
        echo esc_html(
            sprintf(
                /* translators: 1: recipient address, 2: error message */
                __( 'A recent email to %1$s failed: %2$s', 'nimblymail-smtp' ),
                $error['to'],
                $error['error']
            )
        );
        echo ' <a href="' . esc_url( $logs_url ) . '">' . esc_html__( 'View logs', 'nimblymail-smtp' ) . '</a>';
        echo '</p>';
        echo '</div>';
    }
}
