<?php declare( strict_types=1 );

namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Afs\Processing;

use FernleafSystems\Wordpress\Plugin\Shield\DBs\Malware\Ops as MalwareDB;
use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
use FernleafSystems\Wordpress\Services\Services;
use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Malai\QueryMalwareStatusMulti;

class RetrieveMalwareMalaiStatus {

	use PluginControllerConsumer;

	/**
	 * @param MalwareDB\Record[] $records
	 */
	public function updateRecords( array $records, bool $forceCheck = false ) :void {
		$con = self::con();
		/** @var MalwareDB\Update $updater */
		$updater = $con->db_con->malware->getQueryUpdater();

		$required = \array_filter( $records, function ( $record ) use ( $forceCheck ) {
			return $record instanceof MalwareDB\Record && ( $forceCheck || $this->isRecheckRequired( $record ) );
		} );

		if ( !empty( $required ) ) {

			// First update local DB records. ONLY if this successful do we continue.
			$success = (bool)Services::WpDb()->doSql( sprintf(
				'UPDATE `%s` SET %s WHERE `id` IN (%s);',
				$con->db_con->malware->getTable(),
				sprintf( '`last_malai_status_at`=%s', Services::Request()->ts() ),
				\implode( ', ', \array_map(
					function ( $required ) {
						return $required->id;
					},
					$required
				) )
			) );

			if ( $success && $con->caps->canScanMalwareMalai() ) {
				$token = $con->comps->api_token->getToken();
				$statuses = ( new QueryMalwareStatusMulti( $token ) )->retrieve(
					\array_map(
						function ( $record ) {
							return $record->hash_sha256;
						},
						$required
					)
				);

				foreach ( $records as $record ) {
					if ( isset( $statuses[ $record->hash_sha256 ] ) ) {
						$updater->updateRecord( $record, [
							'malai_status'         => $statuses[ $record->hash_sha256 ],
							'last_malai_status_at' => Services::Request()->ts(),
						] );
						$record->malai_status = $statuses[ $record->hash_sha256 ];
					}
				}
			}
		}
	}

	public function single( MalwareDB\Record $record, bool $forceCheck = false ) :string {
		$this->updateRecords( [ $record ], $forceCheck );
		return $record->malai_status;
	}

	private function isRecheckRequired( MalwareDB\Record $record ) :bool {
		$now = Services::Request()->ts();
		$status = $record->malai_status;
		return empty( $status )
			   || ( $status === MalwareStatus::STATUS_UNKNOWN && ( $now - $record->last_malai_status_at > \DAY_IN_SECONDS ) )
			   || ( $status !== MalwareStatus::STATUS_UNKNOWN && ( $now - $record->last_malai_status_at > \WEEK_IN_SECONDS ) );
	}
}