<?php
/**
 * Spellmatic_Scheduler
 *
 * Manages scheduled scan digests via WP-Cron.
 *
 * The digest emails the configured recipient with:
 *   - Count of currently open errors from the most recent scan
 *   - Date the last scan was run
 *   - A nudge to re-scan if the last scan is older than the schedule interval
 *   - A direct link to the Spellmatic dashboard
 *
 * Note: Full automated server-side scanning is Phase 5 (BYOK AI).
 * Phase 4 uses the digest approach because the Harper WASM linter is
 * browser-side; the scheduler emails results from the last browser scan
 * and prompts the admin to run a fresh scan when content has changed.
 *
 * Settings stored under 'spellmatic_settings':
 *   digest_enabled   bool    — whether the cron digest is active
 *   digest_frequency string  — 'weekly' | 'monthly'
 *   digest_email     string  — recipient email (defaults to admin email)
 */

defined( 'ABSPATH' ) || exit;

class Spellmatic_Scheduler {

    /** Cron hook name. */
    const CRON_HOOK = 'spellmatic_digest';

    /** Custom cron interval name for monthly. */
    const MONTHLY_INTERVAL = 'spellmatic_monthly';

    // =========================================================================
    // Init / Teardown
    // =========================================================================

    /**
     * Register custom cron intervals and wire up the cron hook.
     * Called from Spellmatic_Core::init().
     */
    public static function init(): void {
        add_filter( 'cron_schedules', [ self::class, 'add_intervals' ] );
        add_action( self::CRON_HOOK, [ self::class, 'send_digest' ] );
    }

    /**
     * Register the plugin's cron event based on current settings.
     * Call this when settings are saved or on plugin activation.
     */
    public static function schedule(): void {
        $settings = get_option( 'spellmatic_settings', Spellmatic_Core::default_settings() );

        // Always clear first to avoid duplicate events.
        self::unschedule();

        if ( empty( $settings['digest_enabled'] ) ) {
            return;
        }

        $frequency = $settings['digest_frequency'] ?? 'weekly';
        $recurrence = ( 'monthly' === $frequency ) ? self::MONTHLY_INTERVAL : 'weekly';

        if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
            wp_schedule_event( time(), $recurrence, self::CRON_HOOK );
        }
    }

    /**
     * Remove any scheduled cron events for this plugin.
     * Called on plugin deactivation.
     */
    public static function unschedule(): void {
        $timestamp = wp_next_scheduled( self::CRON_HOOK );
        if ( $timestamp ) {
            wp_unschedule_event( $timestamp, self::CRON_HOOK );
        }
    }

    /**
     * Add a 'monthly' cron interval (WP core only ships weekly as the longest).
     */
    public static function add_intervals( array $schedules ): array {
        $schedules[ self::MONTHLY_INTERVAL ] = [
            'interval' => 30 * DAY_IN_SECONDS,
            'display'  => __( 'Once Monthly', 'spellmatic' ),
        ];
        return $schedules;
    }

    // =========================================================================
    // Digest
    // =========================================================================

    /**
     * Build and send the digest email.
     * Hooked to self::CRON_HOOK.
     */
    public static function send_digest(): void {
        global $wpdb;

        $settings = get_option( 'spellmatic_settings', Spellmatic_Core::default_settings() );

        if ( empty( $settings['digest_enabled'] ) ) {
            return;
        }

        $recipient = ! empty( $settings['digest_email'] )
            ? sanitize_email( $settings['digest_email'] )
            : get_option( 'admin_email' );

        if ( ! is_email( $recipient ) ) {
            return;
        }

        // ── Gather stats from the DB ───────────────────────────────────────

        // Count of currently open errors.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom table count for digest email.
        $open_count = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->prefix}spellmatic_results WHERE status = 'open'"
        );

        // Most recent completed scan.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom table; fresh data for digest email.
        $last_scan = $wpdb->get_row(
            "SELECT completed_at, error_count, scanned_items
             FROM {$wpdb->prefix}spellmatic_scans
             WHERE status = 'complete'
             ORDER BY completed_at DESC
             LIMIT 1",
            ARRAY_A
        );

        $dashboard_url = admin_url( 'admin.php?page=spellmatic' );
        $site_name     = get_bloginfo( 'name' );
        $site_url      = get_home_url();

        // ── Build email ────────────────────────────────────────────────────

        $subject = '[' . $site_name . '] Spellmatic — ';

        if ( $open_count > 0 ) {
            $subject .= $open_count . ' spelling ' . ( $open_count === 1 ? 'error' : 'errors' ) . ' need attention';
        } else {
            $subject .= 'All clear — no open errors';
        }

        $body = self::build_email_body( [
            'site_name'     => $site_name,
            'site_url'      => $site_url,
            'dashboard_url' => $dashboard_url,
            'open_count'    => $open_count,
            'last_scan'     => $last_scan,
            'settings'      => $settings,
        ] );

        $headers = [
            'Content-Type: text/html; charset=UTF-8',
            'From: ' . $site_name . ' <' . get_option( 'admin_email' ) . '>',
        ];

        wp_mail( $recipient, $subject, $body, $headers );
    }

    /**
     * Build the HTML email body.
     *
     * @param array $data  Context data for the email.
     * @return string  HTML email.
     */
    private static function build_email_body( array $data ): string {
        $open_count    = (int) $data['open_count'];
        $last_scan     = $data['last_scan'];
        $dashboard_url = esc_url( $data['dashboard_url'] );
        $site_name     = esc_html( $data['site_name'] );
        $site_url      = esc_url( $data['site_url'] );
        $frequency     = $data['settings']['digest_frequency'] ?? 'weekly';

        // Work out if the last scan is overdue.
        $overdue_html = '';
        if ( $last_scan && ! empty( $last_scan['completed_at'] ) ) {
            $scan_time   = strtotime( $last_scan['completed_at'] );
            $days_ago    = (int) floor( ( time() - $scan_time ) / DAY_IN_SECONDS );
            $threshold   = ( 'monthly' === $frequency ) ? 35 : 10;

            if ( $days_ago > $threshold ) {
                $overdue_html = '
                <tr>
                  <td style="background:#FEF3CD;border-left:4px solid #E6A800;padding:14px 20px;border-radius:4px;margin-bottom:16px;">
                    <strong style="color:#5A3E00;">&#9888; Your last scan was ' . (int) $days_ago . ' days ago.</strong><br>
                    <span style="color:#7A5800;font-size:13px;">Content may have changed. Consider running a fresh scan.</span>
                  </td>
                </tr>
                <tr><td style="height:16px;"></td></tr>';
            }
        }

        // Open errors summary block.
        if ( $open_count > 0 ) {
            $summary_bg    = '#FDEDEC';
            $summary_color = '#922B21';
            $summary_icon  = '&#10007;';
            $summary_text  = '<strong>' . $open_count . ' open spelling ' . ( $open_count === 1 ? 'error' : 'errors' ) . '</strong> found on your site.';
        } else {
            $summary_bg    = '#EAFAF1';
            $summary_color = '#1E6B35';
            $summary_icon  = '&#10003;';
            $summary_text  = '<strong>All clear!</strong> No open spelling errors on your site.';
        }

        // Last scan row.
        $last_scan_html = '';
        if ( $last_scan ) {
            $scanned = (int) $last_scan['scanned_items'];
            $found   = (int) $last_scan['error_count'];
            $when    = wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $last_scan['completed_at'] ) );
            $last_scan_html = '
            <tr>
              <td style="font-size:13px;color:#595959;padding-top:8px;">
                Last scan: <strong>' . esc_html( $when ) . '</strong> &mdash;
                scanned ' . $scanned . ' items, found ' . $found . ' errors.
              </td>
            </tr>';
        }

        return '<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
<body style="margin:0;padding:0;background:#F4F6F9;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,sans-serif;">
  <table width="100%" cellpadding="0" cellspacing="0" style="background:#F4F6F9;padding:32px 16px;">
    <tr>
      <td align="center">
        <table width="600" cellpadding="0" cellspacing="0" style="background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08);">

          <!-- Header -->
          <tr>
            <td style="background:#1F4E79;padding:24px 32px;">
              <span style="color:#fff;font-size:20px;font-weight:700;">Spellmatic</span>
              <span style="color:#90CAF9;font-size:13px;margin-left:12px;">Site Digest for ' . $site_name . '</span>
            </td>
          </tr>

          <!-- Body -->
          <tr>
            <td style="padding:32px;">
              <table width="100%" cellpadding="0" cellspacing="0">
                ' . $overdue_html . '

                <!-- Summary block -->
                <tr>
                  <td style="background:' . $summary_bg . ';border-radius:6px;padding:20px 24px;">
                    <span style="font-size:28px;color:' . $summary_color . ';">' . $summary_icon . '</span>
                    <span style="font-size:16px;color:' . $summary_color . ';margin-left:10px;">' . $summary_text . '</span>
                  </td>
                </tr>

                ' . $last_scan_html . '

                <!-- CTA -->
                <tr><td style="height:24px;"></td></tr>
                <tr>
                  <td>
                    <a href="' . $dashboard_url . '"
                       style="display:inline-block;background:#2E75B6;color:#fff;text-decoration:none;
                              padding:12px 28px;border-radius:4px;font-weight:600;font-size:14px;">
                      ' . ( $open_count > 0 ? 'Review &amp; Fix Errors &rarr;' : 'View Dashboard &rarr;' ) . '
                    </a>
                  </td>
                </tr>

                <!-- Site info -->
                <tr><td style="height:24px;"></td></tr>
                <tr>
                  <td style="border-top:1px solid #EEE;padding-top:16px;font-size:12px;color:#999;">
                    Site: <a href="' . $site_url . '" style="color:#2E75B6;">' . $site_name . '</a><br>
                    Digest frequency: ' . ucfirst( $frequency ) . '<br>
                    <a href="' . $dashboard_url . '" style="color:#2E75B6;">Manage Spellmatic settings</a>
                  </td>
                </tr>

              </table>
            </td>
          </tr>

        </table>
      </td>
    </tr>
  </table>
</body>
</html>';
    }

    // =========================================================================
    // REST — send a test digest email on demand
    // =========================================================================

    /**
     * Send a test digest to the configured recipient immediately.
     * REST: POST /spellmatic/v1/digest/test
     */
    public static function send_test( WP_REST_Request $request ): WP_REST_Response {
        self::send_digest();
        $settings  = get_option( 'spellmatic_settings', Spellmatic_Core::default_settings() );
        $recipient = ! empty( $settings['digest_email'] )
            ? sanitize_email( $settings['digest_email'] )
            : get_option( 'admin_email' );

        return new WP_REST_Response( [
            'sent' => true,
            'to'   => $recipient,
        ], 200 );
    }
}