<?php

namespace Licenzo\Modules\EDD;

use Licenzo\Model\Subscription;
use Licenzo\Model\SubscriptionMeta;

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

/**
 * Admin notice for EDD subscriptions that were created on a non-recurring-
 * eligible gateway and are therefore single-cycle (EddGatewayPolicy).
 *
 * Rendered on the WordPress admin Dashboard and Licenzo admin screens
 * when at least one active subscription is marked with the
 * `edd_single_cycle` meta flag and is within a rolling 60-day window of
 * its `expire_at`. The goal is to let the operator reach out before
 * expiry — Licenzo cannot and will not auto-charge these customers.
 *
 * The notice is dismissible per-session (WordPress user meta, not a
 * permanent dismiss) because the underlying state is ongoing and re-
 * surfacing on every admin visit would drown out other notices.
 */
class EddGatewayNotice
{
    public const USER_META_DISMISSED = 'licenzo_edd_single_cycle_notice_dismissed_at';

    public const NOTICE_ID = 'licenzo-edd-single-cycle';

    public const DISMISS_TTL_SECONDS = 86400;

    public static function register(): void
    {
        add_action('admin_notices', [static::class, 'render']);
        add_action('wp_ajax_licenzo_dismiss_edd_single_cycle_notice', [static::class, 'handleDismiss']);
    }

    public static function render(): void
    {
        if (!current_user_can('manage_options')) {
            return;
        }

        if (static::isDismissedRecently()) {
            return;
        }

        $count = static::countActiveSingleCycleSubscriptions();
        if ($count <= 0) {
            return;
        }

        $title = esc_html__('Licenzo: EDD subscriptions without auto-renewal', 'licenzo');
        $body = esc_html(sprintf(
            /* translators: %d: count of single-cycle subscriptions */
            _n(
                '%d active EDD subscription was paid through a gateway that Licenzo cannot auto-renew (Licenzo renews Stripe orders only on v1.1). Its license runs until the current period ends; after that, the customer must re-purchase manually.',
                '%d active EDD subscriptions were paid through gateways that Licenzo cannot auto-renew (Licenzo renews Stripe orders only on v1.1). Their licenses run until the current period ends; after that, customers must re-purchase manually.',
                $count,
                'licenzo'
            ),
            $count
        ));
        $guidance = esc_html__(
            'Plan outreach before expiry: export the affected subscriptions from the Licenzo Admin > Subscriptions screen (filter: gateway-not-stripe) and send a manual renewal reminder. Opting other gateways into recurring eligibility is possible via the licenzo_edd_recurring_eligible_gateways filter for sites with custom EDD Stripe-compatible addons.',
            'licenzo'
        );
        $dismissLabel = esc_html__('Dismiss for 24 hours', 'licenzo');
        $nonce = wp_create_nonce('licenzo_dismiss_' . static::NOTICE_ID);

        printf(
            '<div class="notice notice-warning is-dismissible" data-licenzo-notice="%1$s" data-licenzo-nonce="%2$s">'
                . '<p><strong>%3$s</strong></p>'
                . '<p>%4$s</p>'
                . '<p>%5$s</p>'
                . '<p><button type="button" class="button-link" onclick="licenzoDismissEddSingleCycleNotice(this)">%6$s</button></p>'
                . '</div>'
                . '<script>function licenzoDismissEddSingleCycleNotice(btn){var n=btn.closest("[data-licenzo-notice]");if(!n){return;}var d=new FormData();d.append("action","licenzo_dismiss_edd_single_cycle_notice");d.append("_wpnonce",n.dataset.licenzoNonce);fetch(ajaxurl,{method:"POST",credentials:"same-origin",body:d}).then(function(){n.style.display="none";});}</script>',
            esc_attr(static::NOTICE_ID),
            esc_attr($nonce),
            esc_html($title),
            esc_html($body),
            esc_html($guidance),
            esc_html($dismissLabel)
        );
    }

    public static function handleDismiss(): void
    {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['reason' => 'forbidden'], 403);
        }

        $nonce = isset($_POST['_wpnonce']) ? sanitize_text_field(wp_unslash((string) $_POST['_wpnonce'])) : '';
        if (!wp_verify_nonce($nonce, 'licenzo_dismiss_' . static::NOTICE_ID)) {
            wp_send_json_error(['reason' => 'invalid_nonce'], 400);
        }

        update_user_meta(get_current_user_id(), static::USER_META_DISMISSED, time());
        wp_send_json_success(['dismissed_at' => time()]);
    }

    private static function isDismissedRecently(): bool
    {
        $dismissedAt = (int) get_user_meta(get_current_user_id(), static::USER_META_DISMISSED, true);
        if ($dismissedAt <= 0) {
            return false;
        }

        return (time() - $dismissedAt) < static::DISMISS_TTL_SECONDS;
    }

    private static function countActiveSingleCycleSubscriptions(): int
    {
        try {
            $markedIds = SubscriptionMeta::where('entity_type', 'subscription')
                ->where('meta_key', 'edd_single_cycle')
                ->where('meta_value', '1')
                ->pluck('entity_id')
                ->map(static function ($id) {
                    return (int) $id;
                })
                ->filter()
                ->unique()
                ->values()
                ->all();

            if (empty($markedIds)) {
                return 0;
            }

            return (int) Subscription::whereIn('id', $markedIds)
                ->where('status', Subscription::STATUS_ACTIVE)
                ->count();
        } catch (\Throwable $e) {
            return 0;
        }
    }
}
