<?php

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

class AIEO_Archive_Handlers {

	const BATCH_SIZE      = 5000;
	const MAX_ITERATIONS  = 20;
	const AE_HOT_DAYS     = 365;
	const AE_ARCHIVE_DAYS = 730;
	const RECO_HOT_DAYS   = 30;
	const RECO_ARCHIVE_DAYS = 90;

	
	public static function handle( $gmt_ts ) {
		if ( ! is_string( $gmt_ts ) || $gmt_ts === '' ) {
			$gmt_ts = current_time( 'mysql', true );
		}
		aieo_debug_log( 'AIEO_Archive_Handlers: starting at ' . $gmt_ts );

		$summary = array(
			'addcart_archived'  => 0,
			'addcart_deleted'   => 0,
			'addcart_held'      => 0,
			'reco_archived'     => 0,
			'reco_deleted'      => 0,
			'reco_held'         => 0,
		);

		self::run_for_addcart_events( $gmt_ts, $summary );
		self::run_for_reco_events( $gmt_ts, $summary );
		self::run_for_sessions_archive( $gmt_ts, $summary );
		self::run_for_rollup_retention( $gmt_ts, $summary );

		aieo_debug_log( 'AIEO_Archive_Handlers: done. summary=' . wp_json_encode( $summary ) );
		return $summary;
	}

	
	
	

	
	private static function run_for_sessions_archive( $gmt_ts, array &$summary ) {
		global $wpdb;
		$days = (int) apply_filters( 'aieo_sessions_archive_retention_days', 90 );
		if ( $days < 1 ) { return; }
		$now = strtotime( $gmt_ts . ' UTC' );
		$cut = gmdate( 'Y-m-d H:i:s', $now - $days * DAY_IN_SECONDS );

		$summary['sessions_archive_dropped'] = self::drop_by_ts(
			$wpdb->prefix . 'aieo_sessions_archive', 'archived_at', $cut
		);
		$summary['sessions_statics_archive_dropped'] = self::drop_by_ts(
			$wpdb->prefix . 'aieo_sessions_statics_archive', 'archived_at', $cut
		);
	}

	
	
	

	
	private static function run_for_rollup_retention( $gmt_ts, array &$summary ) {
		global $wpdb;
		$days = (int) apply_filters( 'aieo_rollup_retention_days', 730 );
		if ( $days < 1 ) { return; }
		$now = strtotime( $gmt_ts . ' UTC' );
		$cut = gmdate( 'Y-m-d', $now - $days * DAY_IN_SECONDS );

		foreach ( array(
			'aieo_engagement_daily',
			'aieo_blog_engagement_daily',
			'aieo_cart_removal_daily',
			'aieo_attribution_daily',
			'aieo_reco_daily',
			'aieo_landing_funnel_daily',
		) as $slug ) {
			$summary[ $slug . '_dropped' ] = self::drop_by_ts(
				$wpdb->prefix . $slug, 'date', $cut
			);
		}
	}

	
	
	

	private static function run_for_addcart_events( $gmt_ts, array &$summary ) {
		global $wpdb;
		$hot     = $wpdb->prefix . 'aieo_addcart_events';
		$archive = $wpdb->prefix . 'aieo_addcart_events_archive';
		if ( ! self::table_exists( $hot ) ) { return; }

		self::ensure_archive_table_clone( $hot, $archive );

		$now      = strtotime( $gmt_ts . ' UTC' );
		$hot_cut  = gmdate( 'Y-m-d H:i:s', $now - self::AE_HOT_DAYS * DAY_IN_SECONDS );
		$arch_cut = gmdate( 'Y-m-d H:i:s', $now - self::AE_ARCHIVE_DAYS * DAY_IN_SECONDS );

		
		if ( ! AIEO_Remote_Export_Manager::can_purge_through( 'aieo_addcart_events', $hot_cut ) ) {
			aieo_debug_log( 'AIEO_Archive_Handlers: holding addcart_events purge — remote export not caught up to ' . $hot_cut );
			$summary['addcart_held'] = 1;
		} else {
			list( $moved, $deleted ) = self::archive_then_delete_by_ts(
				$hot, $archive, 'ts_added', $hot_cut
			);
			$summary['addcart_archived'] = $moved;
			$summary['addcart_deleted']  = $deleted;
		}

		
		$summary['addcart_archive_dropped'] = self::drop_by_ts(
			$archive, 'archived_at', $arch_cut
		);
	}

	
	
	

	private static function run_for_reco_events( $gmt_ts, array &$summary ) {
		global $wpdb;
		$hot     = $wpdb->prefix . 'aieo_reco_events';
		$archive = $wpdb->prefix . 'aieo_reco_events_archive';
		if ( ! self::table_exists( $hot ) ) { return; }

		self::ensure_archive_table_clone( $hot, $archive );

		$now      = strtotime( $gmt_ts . ' UTC' );
		$hot_cut  = gmdate( 'Y-m-d H:i:s', $now - self::RECO_HOT_DAYS * DAY_IN_SECONDS );
		$arch_cut = gmdate( 'Y-m-d H:i:s', $now - self::RECO_ARCHIVE_DAYS * DAY_IN_SECONDS );

		if ( ! AIEO_Remote_Export_Manager::can_purge_through( 'aieo_reco_events', $hot_cut ) ) {
			aieo_debug_log( 'AIEO_Archive_Handlers: holding reco_events purge — remote export not caught up to ' . $hot_cut );
			$summary['reco_held'] = 1;
		} else {
			list( $moved, $deleted ) = self::archive_then_delete_by_ts(
				$hot, $archive, 'ts', $hot_cut
			);
			$summary['reco_archived'] = $moved;
			$summary['reco_deleted']  = $deleted;
		}

		$summary['reco_archive_dropped'] = self::drop_by_ts(
			$archive, 'archived_at', $arch_cut
		);
	}

	
	
	

	
	private static function archive_then_delete_by_ts( $hot, $archive, $ts_col, $cutoff ) {
		global $wpdb;
		$moved   = 0;
		$deleted = 0;

		
		
		
		
		
		$cols = self::get_column_names( $hot );
		if ( empty( $cols ) ) { return array( 0, 0 ); }
		$col_list = '`' . implode( '`,`', $cols ) . '`';
		
		$moved = (int) $wpdb->query( $wpdb->prepare(
			"INSERT IGNORE INTO {$archive} ({$col_list}, archived_at)
			 SELECT {$col_list}, UTC_TIMESTAMP()
			   FROM {$hot}
			  WHERE {$ts_col} < %s",
			$cutoff
		) );

		
		for ( $i = 0; $i < self::MAX_ITERATIONS; $i++ ) {
			$d = (int) $wpdb->query( $wpdb->prepare(
				"DELETE FROM {$hot} WHERE {$ts_col} < %s LIMIT %d",
				$cutoff,
				self::BATCH_SIZE
			) );
			$deleted += $d;
			if ( $d < self::BATCH_SIZE ) { break; }
		}

		return array( $moved, $deleted );
	}

	
	private static function drop_by_ts( $table, $ts_col, $cutoff ) {
		global $wpdb;
		if ( ! self::table_exists( $table ) ) { return 0; }
		$total = 0;
		for ( $i = 0; $i < self::MAX_ITERATIONS; $i++ ) {
			$d = (int) $wpdb->query( $wpdb->prepare(
				"DELETE FROM {$table} WHERE {$ts_col} < %s LIMIT %d",
				$cutoff,
				self::BATCH_SIZE
			) );
			$total += $d;
			if ( $d < self::BATCH_SIZE ) { break; }
		}
		return $total;
	}

	
	
	

	
	private static function ensure_archive_table_clone( $hot, $archive ) {
		global $wpdb;
		if ( self::table_exists( $archive ) ) { return; }

		
		$row = $wpdb->get_row( "SHOW CREATE TABLE {$hot}", ARRAY_N );
		if ( empty( $row[1] ) ) { return; }
		$create = (string) $row[1];

		
		$create = preg_replace(
			'/^CREATE TABLE `?[^`(\s]+`?\s*\(/',
			'CREATE TABLE `' . $archive . '` (',
			$create,
			1
		);

		
		$create = preg_replace( '/\s+AUTO_INCREMENT=\d+/i', '', $create );

		
		
		$lines = preg_split( '/\r?\n/', $create );
		$keep  = array();
		foreach ( $lines as $line ) {
			$ltrim = ltrim( $line );
			if ( stripos( $ltrim, 'UNIQUE KEY' ) === 0 && stripos( $ltrim, 'event_id' ) !== false ) {
				continue;
			}
			$keep[] = $line;
		}
		$create = implode( "\n", $keep );

		
		if ( preg_match( '/\)(\s*ENGINE=|\s*DEFAULT CHARSET=|\s*COLLATE=|\s*;|\s*$)/i', $create, $m, PREG_OFFSET_CAPTURE ) ) {
			$pos    = $m[0][1];
			$inject = ",\n  `archived_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  KEY `archived_at` (`archived_at`)\n";
			$create = substr( $create, 0, $pos ) . $inject . substr( $create, $pos );
		}

		$wpdb->query( $create );
	}

	private static function get_column_names( $table ) {
		global $wpdb;
		$rows = $wpdb->get_results( "SHOW COLUMNS FROM {$table}", ARRAY_A );
		$cols = array();
		foreach ( (array) $rows as $r ) {
			if ( ! empty( $r['Field'] ) ) { $cols[] = (string) $r['Field']; }
		}
		return $cols;
	}

	private static function table_exists( $table ) {
		global $wpdb;
		return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
	}
}
