<?php

declare(strict_types=1);

namespace FormConnector\Features\Notifications;

use FormConnector\Core\Settings\Settings;

defined('ABSPATH') || exit;

/**
 * Email Notification Manager
 *
 * Sends admin email alerts when submissions fail or
 * retry attempts are permanently exhausted.
 */
class EmailNotifier {

    private static ?EmailNotifier $instance = null;

    /** Transient key for tracking consecutive failures */
    private const FAILURE_COUNT_TRANSIENT = 'fc_consecutive_failures';

    /** Option key for last notification timestamp */
    private const LAST_NOTIFIED_OPTION = 'fc_last_failure_notification';

    /** Minimum interval between notification emails (1 hour) */
    private const NOTIFICATION_COOLDOWN = 3600;

    public static function get_instance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Register hooks for failure notifications.
     */
    public function register_hooks(): void {
        // Listen for retry queue permanent failures
        add_action('fc_retry_permanently_failed', [$this, 'on_retry_permanently_failed'], 10, 2);
    }

    /**
     * Called by SubmissionHandler when a submission fails.
     */
    public function on_submission_failed(array $context): void {
        $settings = Settings::get_instance();
        if (!$settings->get('failure_notifications_enabled', true)) {
            return;
        }

        $threshold = (int) $settings->get('failure_notification_threshold', 3);

        // Increment consecutive failure counter
        $count = (int) get_transient(self::FAILURE_COUNT_TRANSIENT);
        $count++;
        set_transient(self::FAILURE_COUNT_TRANSIENT, $count, DAY_IN_SECONDS);

        if ($count >= $threshold) {
            $this->send_failure_notification($context, $count);
            // Reset counter after notification
            delete_transient(self::FAILURE_COUNT_TRANSIENT);
        }
    }

    /**
     * Called when a submission succeeds — reset the failure counter.
     */
    public function on_submission_success(): void {
        delete_transient(self::FAILURE_COUNT_TRANSIENT);
    }

    /**
     * Handle permanently failed retry.
     *
     * @param array $item The retry queue item
     * @param string $error The final error message
     */
    public function on_retry_permanently_failed(array $item, string $error): void {
        $settings = Settings::get_instance();
        if (!$settings->get('failure_notifications_enabled', true)) {
            return;
        }

        // Always notify on permanent retry failure (respecting cooldown)
        $this->send_retry_failed_notification($item, $error);
    }

    /**
     * Send a notification about consecutive submission failures.
     */
    private function send_failure_notification(array $context, int $failure_count): void {
        if (!$this->can_send_notification()) {
            return;
        }

        $admin_email = $this->get_notification_email();
        $site_name = get_bloginfo('name');

        $subject = sprintf(
            '[%s] CareHQ Connector: %d consecutive submission failures',
            $site_name,
            $failure_count
        );

        $form_name = $context['form_name'] ?? 'Unknown';
        $error = $context['error'] ?? 'Unknown error';
        $location = $context['location_name'] ?? $context['location_id'] ?? 'Unknown';

        $body = sprintf(
            "CareHQ Connector has detected %d consecutive failed form submissions.\n\n" .
            "Latest failure details:\n" .
            "- Form: %s\n" .
            "- Location: %s\n" .
            "- Error: %s\n" .
            "- Time: %s\n\n" .
            "The failed submission has been added to the retry queue and will be retried automatically.\n\n" .
            "Please check your CareHQ API settings and connection.\n\n" .
            "View logs: %s\n\n" .
            "— CareHQ Connector",
            $failure_count,
            $form_name,
            $location,
            $error,
            current_time('mysql'),
            admin_url('admin.php?page=' . FC_SETTINGS_SLUG . '#logs')
        );

        wp_mail($admin_email, $subject, $body);
        $this->record_notification_sent();
    }

    /**
     * Send notification about a permanently failed retry.
     */
    private function send_retry_failed_notification(array $item, string $error): void {
        if (!$this->can_send_notification()) {
            return;
        }

        $admin_email = $this->get_notification_email();
        $site_name = get_bloginfo('name');

        $subject = sprintf(
            '[%s] CareHQ Connector: Submission permanently failed after %d retries',
            $site_name,
            $item['max_retries'] ?? 5
        );

        $body = sprintf(
            "A form submission has permanently failed after exhausting all retry attempts.\n\n" .
            "Details:\n" .
            "- Form: %s (%s)\n" .
            "- Location: %s\n" .
            "- Retries attempted: %d / %d\n" .
            "- Original submission: %s\n" .
            "- Final error: %s\n\n" .
            "This submission will NOT be retried automatically. " .
            "You can manually retry it from the retry queue in the plugin settings.\n\n" .
            "View retry queue: %s\n\n" .
            "— CareHQ Connector",
            $item['form_name'] ?? 'Unknown',
            $item['form_plugin'] ?? '',
            $item['location_name'] ?? $item['location_id'] ?? 'Unknown',
            $item['retry_count'] ?? 0,
            $item['max_retries'] ?? 5,
            $item['created_at'] ?? '',
            $error,
            admin_url('admin.php?page=' . FC_SETTINGS_SLUG . '#settings')
        );

        wp_mail($admin_email, $subject, $body);
        $this->record_notification_sent();
    }

    /**
     * Check if enough time has passed since the last notification.
     */
    private function can_send_notification(): bool {
        $last_sent = (int) get_option(self::LAST_NOTIFIED_OPTION, 0);
        return (time() - $last_sent) >= self::NOTIFICATION_COOLDOWN;
    }

    /**
     * Record that a notification was just sent.
     */
    private function record_notification_sent(): void {
        update_option(self::LAST_NOTIFIED_OPTION, time());
    }

    /**
     * Get the email address to send notifications to.
     */
    private function get_notification_email(): string {
        $settings = Settings::get_instance();
        $custom_email = $settings->get('notification_email', '');

        if (!empty($custom_email) && is_email($custom_email)) {
            return $custom_email;
        }

        return get_option('admin_email');
    }
}
