<?php
/**
 * Logger maintenance helpers.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use MailDoctor\Helpers\Settings;
use DateTimeImmutable;
use DateTimeZone;

trait Logger_Maintenance_Trait {


	/**
	 * Attempt to prune logs older than retention window.
	 *
	 * @return void
	 */
	public static function maybe_prune_logs( $unused = null ): void {
	 // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
		global $wpdb;

		$periods       = Settings::retention_periods();
		$now           = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
		$sent_days     = (int) ( $periods['sent'] ?? 90 );
		$failed_days   = (int) ( $periods['failed'] ?? 30 );
		$fallback_days = (int) ( $periods['fallback'] ?? 30 );
		$payload_days  = (int) ( $periods['payload'] ?? 14 );

		$table = self::table_name();

		if ( $sent_days > 0 ) {
			$cutoff = $now->modify( sprintf( '-%d days', $sent_days ) )->format( 'Y-m-d H:i:s' );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"DELETE FROM {$table} WHERE status = %s AND created_at < %s",
					'sent',
					$cutoff
				)
			);
		}

		if ( $failed_days > 0 ) {
			$cutoff = $now->modify( sprintf( '-%d days', $failed_days ) )->format( 'Y-m-d H:i:s' );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"DELETE FROM {$table} WHERE status = %s AND created_at < %s",
					'failed',
					$cutoff
				)
			);
		}

		if ( $fallback_days > 0 ) {
			$cutoff = $now->modify( sprintf( '-%d days', $fallback_days ) )->format( 'Y-m-d H:i:s' );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"DELETE FROM {$table} WHERE created_at < %s",
					$cutoff
				)
			);
		}

		if ( $payload_days > 0 ) {
			$cutoff = $now->modify( sprintf( '-%d days', $payload_days ) )->format( 'Y-m-d H:i:s' );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"UPDATE {$table} SET payload = NULL WHERE created_at < %s AND payload IS NOT NULL",
					$cutoff
				)
			);
		}
	}

	/**
	 * Move aged logs into archive storage.
	 *
	 * @return void
	 */
	public static function archive_old_logs(): void {
		self::ensure_archive_table();

		global $wpdb;

		$table      = self::table_name();
		$archive    = self::archive_table_name();
		$cutoff     = gmdate( 'Y-m-d H:i:s', time() - ( 180 * DAY_IN_SECONDS ) );
		$batch      = 200;
		$columns    = self::log_columns();
		$column_sql = implode( ',', $columns );

		do {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$ids = $wpdb->get_col(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"SELECT id FROM {$table} WHERE created_at < %s ORDER BY id ASC LIMIT %d",
					$cutoff,
					$batch
				)
			);

			if ( empty( $ids ) ) {
				break;
			}

			$id_list   = implode( ',', array_map( 'intval', $ids ) );
			$timestamp = gmdate( 'Y-m-d H:i:s' );

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table and column names from internal methods.
			$wpdb->query(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
					"INSERT INTO {$archive} ({$column_sql}, archived_at) SELECT {$column_sql}, %s FROM {$table} WHERE id IN ({$id_list})",
					$timestamp
				)
			);

			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query( "DELETE FROM {$table} WHERE id IN ({$id_list})" );
		} while ( count( $ids ) === $batch );
	}

	/**
	 * Ensure any active logs are marked failed on shutdown.
	 *
	 * @return void
	 */
	public static function finalize_open_logs( $unused = null ): void {
	 // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
		if ( empty( self::$active ) || ! is_array( self::$active ) ) {
			return;
		}

		$open_logs = array_keys( self::$active );

		foreach ( $open_logs as $log_id ) {
			if ( empty( $log_id ) ) {
				continue;
			}
			
			self::mark_failed(
				(int) $log_id,
				'The send process ended before completion. The email will be retried automatically.'
			);
		}
	}
}
