<?php
/**
 * @license GPL-2.0-or-later
 * @link    https://wordpress.org/plugins/pressio-crm
 */
namespace PressioCRM\Modules;

defined( 'ABSPATH' ) || exit;

use PressioCRM\Framework\Module;

class NotificationsModule extends Module {

	public function register(): void {
		// No container bindings needed for this module.
	}

	public function boot(): void {
		add_action( 'pressio_crm_daily_digest', [ $this, 'send_digest' ] );
		add_action( 'pressio_crm_settings_saved', [ $this, 'on_settings_saved' ] );
		add_action( 'admin_notices', [ $this, 'maybe_warn_cron_disabled' ] );

		// Only schedule if not already queued — avoids clearing and recreating
		// the event on every page load.
		if ( ! wp_next_scheduled( 'pressio_crm_daily_digest' ) ) {
			$this->schedule_digest( get_option( 'pressio_crm_settings', [] ) );
		}
	}

	/**
	 * Show an admin notice when WP Cron is disabled via constant AND the digest
	 * is enabled — so the user knows their digest emails will never fire.
	 */
	public function maybe_warn_cron_disabled(): void {
		if ( ! defined( 'DISABLE_WP_CRON' ) || ! DISABLE_WP_CRON ) {
			return;
		}

		$settings = get_option( 'pressio_crm_settings', [] );
		if ( empty( $settings['digest_enabled'] ) ) {
			return;
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		printf(
			'<div class="notice notice-warning"><p>%s</p></div>',
			esc_html__(
				'Pressio CRM: WP-Cron is disabled on this site (DISABLE_WP_CRON is true). Daily digest emails will not be sent unless you configure a real server cron to call wp-cron.php.',
				'pressio-crm'
			)
		);
	}

	public function on_settings_saved( array $settings ): void {
		$this->schedule_digest( $settings );
	}

	/**
	 * Query overdue / due-today tasks and email a digest to the site admin.
	 *
	 * Runs as a WP-Cron callback — no HTTP context, no current user.
	 * Uses wp_mail() directly rather than the Mailer class because admin
	 * digests don't need template rendering overhead.
	 */
	public function send_digest(): void {
		$settings = get_option( 'pressio_crm_settings', [] );

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

		$recipient = ! empty( $settings['digest_recipient'] ) && is_email( $settings['digest_recipient'] )
			? $settings['digest_recipient']
			: get_option( 'admin_email' );

		global $wpdb;

		$tasks_table    = $wpdb->prefix . 'pcrm_tasks';
		$contacts_table = $wpdb->prefix . 'pcrm_contacts';

		// One query with a LEFT JOIN so we get the contact name without N+1.
		// Only tasks that are not completed, not soft-deleted, and due on or before now.
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$tasks = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT
					t.id,
					t.title,
					t.due_date,
					t.contact_id,
					c.first_name,
					c.last_name
				 FROM %i t
				 LEFT JOIN %i c
				     ON c.id = t.contact_id
				     AND c.deleted_at IS NULL
				 WHERE t.status != %s
				   AND t.deleted_at IS NULL
				   AND t.due_date <= %s
				 ORDER BY t.due_date ASC
				 LIMIT 50',
				$tasks_table,
				$contacts_table,
				'completed',
				current_time( 'mysql', true ) // UTC datetime — matches DB storage
			)
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		if ( empty( $tasks ) ) {
			return;
		}

		$count = count( $tasks );

		$subject_tpl = ! empty( $settings['digest_subject_template'] )
			? $settings['digest_subject_template']
			// translators: %d: number of overdue/due-today follow-up tasks.
			: __( 'Pressio CRM: {{count}} follow-up(s) need your attention', 'pressio-crm' );

		$subject = esc_html( str_replace( '{{count}}', (string) $count, $subject_tpl ) );

		$intro_tpl = ! empty( $settings['digest_intro_template'] )
			? $settings['digest_intro_template']
			// translators: %d: number of tasks.
			: __( 'You have {{count}} task(s) that need your attention:', 'pressio-crm' );

		$intro = esc_html( str_replace( '{{count}}', (string) $count, $intro_tpl ) );

		$tasks_url = admin_url( 'admin.php?page=pressio-crm#/tasks' );

		$rows = '';
		foreach ( $tasks as $task ) {
			$title   = esc_html( $task->title );
			$due     = esc_html( $task->due_date );
			$contact = ( $task->first_name || $task->last_name )
				? esc_html( trim( $task->first_name . ' ' . $task->last_name ) )
				: '';

			$contact_part = $contact
				? ' &mdash; ' . $contact
				: '';

			$rows .= '<li>' . $title . $contact_part . ' <em>(' . $due . ')</em></li>' . "\n";
		}

		$body = '<!DOCTYPE html><html><body>' . "\n"
			. '<p>' . esc_html__( 'Hi,', 'pressio-crm' ) . '</p>' . "\n"
			. '<p>' . $intro . '</p>' . "\n"
			. '<ul>' . "\n"
			. $rows
			. '</ul>' . "\n"
			. '<p><a href="' . esc_url( $tasks_url ) . '">'
			. esc_html__( 'View all tasks in Pressio CRM', 'pressio-crm' )
			. '</a></p>' . "\n"
			. '</body></html>';

		$headers = [ 'Content-Type: text/html; charset=UTF-8' ];

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

	private function schedule_digest( array $settings ): void {
		wp_clear_scheduled_hook( 'pressio_crm_daily_digest' );

		if ( isset( $settings['digest_enabled'] ) && ! $settings['digest_enabled'] ) {
			return;
		}

		$hour = isset( $settings['digest_hour'] ) ? (int) $settings['digest_hour'] : 8;
		$hour = ( $hour >= 0 && $hour <= 23 ) ? $hour : 8;

		// Calculate today's run time in UTC.
		$now      = time();
		$today    = gmdate( 'Y-m-d', $now );
		$next_run = strtotime( $today . ' ' . sprintf( '%02d', $hour ) . ':00:00 UTC' );

		// If today's slot has already passed, schedule for tomorrow.
		if ( $next_run <= $now ) {
			$next_run = strtotime( '+1 day', $next_run );
		}

		wp_schedule_event( $next_run, 'daily', 'pressio_crm_daily_digest' );
	}
}
