<?php
/**
 * Newsletter sender: queue recipients on submit, process N per WP-cron tick.
 *
 * @package SuiteMkt3k
 */

namespace SuiteMkt3k\Modules\Newsletter;

use SuiteMkt3k\Email\Mailer;
use SuiteMkt3k\Installer;
use SuiteMkt3k\Modules\Settings\Settings_Manager;
use SuiteMkt3k\Modules\Subscribers\Subscriber_Manager;
use SuiteMkt3k\Utils\Logger;

defined( 'ABSPATH' ) || exit;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching

final class Newsletter_Sender {

	public static function register(): void {
		add_action( 'suitemkt3k_send_newsletter_batch', array( __CLASS__, 'process_batch' ), 10, 1 );
	}

	public static function queue_campaign( int $newsletter_id ): int {
		global $wpdb;
		$row = Newsletter_Manager::get( $newsletter_id );
		if ( ! $row ) {
			return 0;
		}

		$wpdb->delete(
			Newsletter_Manager::recipients_table(),
			array( 'newsletter_id' => $newsletter_id ),
			array( '%d' )
		);

		$recipients = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT id, email FROM %i WHERE status = %s',
				Subscriber_Manager::table(),
				Subscriber_Manager::STATUS_ACTIVE
			),
			ARRAY_A
		);

		$inserted = 0;
		foreach ( (array) $recipients as $sub ) {
			$hash = bin2hex( random_bytes( 32 ) );
			$ok   = $wpdb->insert(
				Newsletter_Manager::recipients_table(),
				array(
					'newsletter_id'  => $newsletter_id,
					'subscriber_id'  => (int) $sub['id'],
					'email'          => (string) $sub['email'],
					'tracking_hash'  => $hash,
					'status'         => 'queued',
				),
				array( '%d', '%d', '%s', '%s', '%s' )
			);
			if ( false !== $ok ) {
				$inserted++;
			}
		}

		$wpdb->update(
			Newsletter_Manager::table(),
			array(
				'status'           => Newsletter_Manager::STATUS_SENDING,
				'recipients_count' => $inserted,
			),
			array( 'id' => $newsletter_id ),
			array( '%s', '%d' ),
			array( '%d' )
		);

		wp_schedule_single_event( time() + 1, 'suitemkt3k_send_newsletter_batch', array( $newsletter_id ) );
		Logger::info( 'newsletter', 'Queued campaign', array( 'id' => $newsletter_id, 'recipients' => $inserted ) );
		return $inserted;
	}

	public static function process_batch( int $newsletter_id ): void {
		global $wpdb;
		$row = Newsletter_Manager::get( $newsletter_id );
		if ( ! $row ) {
			return;
		}
		$batch    = (int) ( Settings_Manager::get( 'newsletter', 'batch_size' ) ?? 50 );
		$interval = (int) ( Settings_Manager::get( 'newsletter', 'batch_interval' ) ?? 60 );
		$batch    = max( 1, min( 500, $batch ) );

		$queued = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT r.*, s.name, s.unsubscribe_token FROM %i r LEFT JOIN %i s ON s.id = r.subscriber_id WHERE r.newsletter_id = %d AND r.status = %s ORDER BY r.id ASC LIMIT %d',
				Newsletter_Manager::recipients_table(),
				Subscriber_Manager::table(),
				$newsletter_id,
				'queued',
				$batch
			),
			ARRAY_A
		);

		if ( empty( $queued ) ) {
			$wpdb->update(
				Newsletter_Manager::table(),
				array(
					'status'  => Newsletter_Manager::STATUS_SENT,
					'sent_at' => current_time( 'mysql', true ),
				),
				array( 'id' => $newsletter_id ),
				array( '%s', '%s' ),
				array( '%d' )
			);
			return;
		}

		$mailer = new Mailer();
		foreach ( $queued as $rcp ) {
			$subscriber = array(
				'name'              => $rcp['name'] ?? '',
				'email'             => $rcp['email'],
				'unsubscribe_token' => $rcp['unsubscribe_token'] ?? '',
			);
			$html = Newsletter_Manager::render_for_subscriber( $row, $subscriber, $rcp['tracking_hash'] );
			$unsub = Subscriber_Manager::unsubscribe_url( $subscriber['unsubscribe_token'] ?? '' );
			$ok   = $mailer->send(
				array(
					'to'               => $rcp['email'],
					'subject'          => $row['subject'],
					'html'             => $html,
					'context'          => 'newsletter',
					'entity_id'        => $newsletter_id,
					'tracking_hash'    => $rcp['tracking_hash'],
					'unsubscribe_url'  => $unsub,
				)
			);
			$wpdb->update(
				Newsletter_Manager::recipients_table(),
				array(
					'status'  => $ok ? 'sent' : 'failed',
					'sent_at' => current_time( 'mysql', true ),
				),
				array( 'id' => (int) $rcp['id'] ),
				array( '%s', '%s' ),
				array( '%d' )
			);
		}

		$remaining = (int) $wpdb->get_var(
			$wpdb->prepare(
				'SELECT COUNT(*) FROM %i WHERE newsletter_id = %d AND status = %s',
				Newsletter_Manager::recipients_table(),
				$newsletter_id,
				'queued'
			)
		);
		if ( $remaining > 0 ) {
			wp_schedule_single_event( time() + max( 30, $interval ), 'suitemkt3k_send_newsletter_batch', array( $newsletter_id ) );
		} else {
			$wpdb->update(
				Newsletter_Manager::table(),
				array(
					'status'  => Newsletter_Manager::STATUS_SENT,
					'sent_at' => current_time( 'mysql', true ),
				),
				array( 'id' => $newsletter_id ),
				array( '%s', '%s' ),
				array( '%d' )
			);
		}
	}
}
