<?php

namespace SugarCalendarBookings\UsageTracking;

use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Support\Tasks\AbstractTask;
use SugarCalendarBookings\Support\Tasks\TaskRegistry;

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

/**
 * Class SendUsageTask.
 *
 * Sends anonymous usage data to the tracking endpoint on a weekly schedule.
 *
 * @since 1.4.0
 */
class SendUsageTask extends AbstractTask {

	/**
	 * Action name for this task.
	 *
	 * @since 1.4.0
	 */
	const ACTION = 'sugar_calendar_bookings_send_usage_data';

	/**
	 * Server URL to send tracking data to.
	 *
	 * @since 1.4.0
	 */
	const TRACK_URL = 'https://scbusage.com/v1/sugarcalendarbookingstrack';

	/**
	 * Option name to store the timestamp of the last run.
	 *
	 * @since 1.4.0
	 */
	const LAST_RUN = 'sugar_calendar_bookings_send_usage_last_run';

	/**
	 * Class constructor.
	 *
	 * @since 1.4.0
	 */
	public function __construct() {

		parent::__construct( self::ACTION );
	}

	/**
	 * Initialize the task with all the proper checks.
	 *
	 * @since 1.4.0
	 */
	public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		// Always register the action handler so AS can fire the callback.
		// The process() method has its own is_enabled() guard.
		add_action( self::ACTION, [ $this, 'process' ] );
		add_action( 'action_scheduler_after_process_queue', [ $this, 'cleanup' ] );

		$usage_tracking = Plugin::get( UsageTracking::class );

		// Only schedule if tracking is enabled.
		if ( $usage_tracking === null || ! $usage_tracking->is_enabled() ) {
			return;
		}

		// Schedule if not already scheduled.
		if ( TaskRegistry::is_scheduled( self::ACTION ) !== false ) {
			return;
		}

		$this->recurring( $this->generate_start_date(), WEEK_IN_SECONDS )
			->unique()
			->register();
	}

	/**
	 * Generate a random start date within the next week from next Sunday.
	 *
	 * Distributes server load by randomizing when each site sends data.
	 *
	 * @since 1.4.0
	 *
	 * @return int
	 */
	private function generate_start_date() {

		$tracking            = [];
		$tracking['days']    = wp_rand( 0, 6 ) * DAY_IN_SECONDS;
		$tracking['hours']   = wp_rand( 0, 23 ) * HOUR_IN_SECONDS;
		$tracking['minutes'] = wp_rand( 0, 59 ) * MINUTE_IN_SECONDS;
		$tracking['seconds'] = wp_rand( 0, 59 );

		return strtotime( 'next sunday' ) + array_sum( $tracking );
	}

	/**
	 * Send the actual data in a POST request.
	 *
	 * This is executed in a separate process via Action Scheduler.
	 *
	 * @since 1.4.0
	 */
	public function process() {

		$last_run = get_option( self::LAST_RUN );

		// Make sure we do not run it more than once a day.
		if (
			$last_run !== false &&
			( time() - $last_run ) < DAY_IN_SECONDS
		) {
			return;
		}

		$usage_tracking = Plugin::get( UsageTracking::class );

		// Self-cancel the recurring schedule if tracking was disabled after scheduling.
		if ( $usage_tracking === null || ! $usage_tracking->is_enabled() ) {
			$this->cancel();

			return;
		}

		$body       = $usage_tracking->get_data();
		$user_agent = $usage_tracking->get_user_agent();

		// Send data to the usage tracking API.
		$response = wp_remote_post(
			self::TRACK_URL,
			[
				'timeout'     => 5,
				'redirection' => 0,
				'httpversion' => '1.1',
				'blocking'    => true,
				'body'        => $body,
				'user-agent'  => $user_agent,
			]
		);

		if ( is_wp_error( $response ) ) {
			return;
		}

		// Update the last run option to the current timestamp.
		update_option( self::LAST_RUN, time(), false );
	}

	/**
	 * Cleanup completed tasks.
	 *
	 * @since 1.4.0
	 */
	public function cleanup() {

		$this->remove_completed( 10 );
	}
}
