<?php
/**
 * Retention cleanup for completed import jobs and encrypted source files.
 *
 * @package EmberPrice
 */

namespace EmberPrice\Ingestion;

use EmberPrice\Core\Crypto;
use EmberPrice\Core\Jobs;
use EmberPrice\Core\Rows;
use EmberPrice\Core\Settings;
use EmberPrice\Core\Snapshots;

defined( 'ABSPATH' ) || exit;

/**
 * Deletes terminal jobs after a configurable audit window. Supplier
 * settings and learned aliases are intentionally retained.
 */
final class JobRetention {

	public const HOOK = 'embp_job_retention_cleanup';

	private const GROUP                  = 'emberprice';
	private const DEFAULT_RETENTION_DAYS = 90;

	/**
	 * Site settings.
	 *
	 * @var Settings
	 */
	private Settings $settings;

	/**
	 * Job storage.
	 *
	 * @var Jobs
	 */
	private Jobs $jobs;

	/**
	 * Imported row storage.
	 *
	 * @var Rows
	 */
	private Rows $rows;

	/**
	 * Rollback snapshot storage.
	 *
	 * @var Snapshots
	 */
	private Snapshots $snapshots;

	/**
	 * Encrypted upload storage.
	 *
	 * @var UploadStorage
	 */
	private UploadStorage $uploads;

	/**
	 * Builds the retention service.
	 *
	 * @param Settings|null      $settings  Settings accessor.
	 * @param Jobs|null          $jobs      Job storage.
	 * @param Rows|null          $rows      Row storage.
	 * @param Snapshots|null     $snapshots Snapshot storage.
	 * @param UploadStorage|null $uploads   Encrypted upload storage.
	 */
	public function __construct(
		?Settings $settings = null,
		?Jobs $jobs = null,
		?Rows $rows = null,
		?Snapshots $snapshots = null,
		?UploadStorage $uploads = null
	) {
		$this->settings  = $settings ?? new Settings( Crypto::for_site() );
		$this->jobs      = $jobs ?? new Jobs();
		$this->rows      = $rows ?? new Rows();
		$this->snapshots = $snapshots ?? new Snapshots();
		$this->uploads   = $uploads ?? new UploadStorage();
	}

	/**
	 * Registers and schedules the daily cleanup.
	 */
	public function register(): void {
		add_action( self::HOOK, array( $this, 'run' ) );

		if ( false === as_next_scheduled_action( self::HOOK, array(), self::GROUP ) ) {
			as_schedule_recurring_action( time(), DAY_IN_SECONDS, self::HOOK, array(), self::GROUP, true );
		}
	}

	/**
	 * Deletes at most 100 old jobs per daily run.
	 */
	public function run(): void {
		$days = max( 30, $this->settings->get_int( 'job_retention_days', self::DEFAULT_RETENTION_DAYS ) );

		foreach ( $this->jobs->terminal_older_than( $days ) as $job ) {
			$job_id = (int) $job['id'];

			$this->rows->delete_by_job( $job_id );
			$this->snapshots->delete_by_job( $job_id );
			$this->uploads->delete_by_hash( (string) $job['file_hash'] );
			$this->jobs->delete( $job_id );
		}
	}
}
