<?php
namespace R2_Offload\Migration;

use R2_Offload\DB;
use R2_Offload\Logger;
use R2_Offload\Media\Path_Resolver;
use R2_Offload\Settings;

defined( 'ABSPATH' ) || exit;

final class Scanner {

	public const STATE_OPTION = 'r2_offload_scan_state';

	private Settings $settings;
	private Logger $logger;

	public function __construct( Settings $settings, Logger $logger ) {
		$this->settings = $settings;
		$this->logger   = $logger;
	}

	public function reset_state(): void {
		delete_option( self::STATE_OPTION );
	}

	public function get_state(): array {
		return wp_parse_args(
			(array) get_option( self::STATE_OPTION, [] ),
			[
				'last_id'        => 0,
				'scanned'        => 0,
				'queued'         => 0,
				'skipped'        => 0,
				'bytes_total'    => 0,
				'finished'       => 0,
				'started_at'     => '',
				'dry_run'        => 0,
			]
		);
	}

	private function save_state( array $state ): void {
		update_option( self::STATE_OPTION, $state, false );
	}

	public function start( bool $dry_run = false ): void {
		$this->reset_state();
		$this->save_state(
			array_merge(
				$this->get_state(),
				[
					'started_at' => current_time( 'mysql' ),
					'dry_run'    => $dry_run ? 1 : 0,
				]
			)
		);
	}

	/**
	 * Scan a chunk of attachments. Returns state snapshot.
	 */
	public function scan_chunk( int $batch_size = 200 ): array {
		global $wpdb;
		$state = $this->get_state();
		if ( $state['finished'] ) {
			return $state;
		}

		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT ID FROM {$wpdb->posts}
				 WHERE post_type = 'attachment' AND ID > %d
				 ORDER BY ID ASC LIMIT %d",
				(int) $state['last_id'],
				$batch_size
			)
		);

		if ( empty( $rows ) ) {
			$state['finished'] = 1;
			$this->save_state( $state );
			$this->logger->info( 'Scan complete.', 'scan', $state );
			return $state;
		}

		$dry    = (bool) $state['dry_run'];
		$bucket = (string) $this->settings->get( 'bucket' );
		$prefix = $this->settings->effective_prefix();

		foreach ( $rows as $row ) {
			$attachment_id     = (int) $row->ID;
			$state['last_id']  = $attachment_id;
			$state['scanned']++;

			$paths = Path_Resolver::attachment_files( $attachment_id );
			if ( empty( $paths ) ) {
				$state['skipped']++;
				continue;
			}

			$size = 0;
			foreach ( $paths as $p ) {
				$size += (int) @filesize( $p );
			}
			$state['bytes_total'] += $size;

			$existing = DB::get_item( $attachment_id );
			if ( $existing && $existing->status === 'offloaded' ) {
				$state['skipped']++;
				continue;
			}

			if ( ! $dry ) {
				DB::upsert_item(
					$attachment_id,
					[
						'status'        => 'pending',
						'provider'      => $this->settings->provider(),
						'bucket'        => $bucket,
						'object_prefix' => $prefix,
						'bytes_total'   => $size,
						'updated_at'    => current_time( 'mysql' ),
					]
				);
				$state['queued']++;
			} else {
				$state['queued']++;
			}
		}

		$this->save_state( $state );
		return $state;
	}
}
