<?php
namespace R2_Offload\Admin;

use R2_Offload\Media\Pruner;
use R2_Offload\Migration\Migrator;
use R2_Offload\Migration\Scanner;
use R2_Offload\Migration\Verifier;
use R2_Offload\Settings;

defined( 'ABSPATH' ) || exit;

final class Ajax {

	private Scanner $scanner;
	private Migrator $migrator;
	private Verifier $verifier;
	private Pruner $pruner;
	private Settings $settings;

	public function __construct( Scanner $scanner, Migrator $migrator, Verifier $verifier, Pruner $pruner, Settings $settings ) {
		$this->scanner  = $scanner;
		$this->migrator = $migrator;
		$this->verifier = $verifier;
		$this->pruner   = $pruner;
		$this->settings = $settings;
	}

	public function register(): void {
		add_action( 'wp_ajax_r2_offload_scan_start', [ $this, 'scan_start' ] );
		add_action( 'wp_ajax_r2_offload_scan_tick', [ $this, 'scan_tick' ] );
		add_action( 'wp_ajax_r2_offload_scan_reset', [ $this, 'scan_reset' ] );
		add_action( 'wp_ajax_r2_offload_migrate', [ $this, 'migrate' ] );
		add_action( 'wp_ajax_r2_offload_migrate_tick', [ $this, 'migrate_tick' ] );
		add_action( 'wp_ajax_r2_offload_progress', [ $this, 'progress' ] );
		add_action( 'wp_ajax_r2_offload_verify', [ $this, 'verify' ] );
		add_action( 'wp_ajax_r2_offload_retry_one', [ $this, 'retry_one' ] );
		add_action( 'wp_ajax_r2_offload_install_deps', [ $this, 'install_deps' ] );
		add_action( 'wp_ajax_r2_offload_debug', [ $this, 'debug' ] );
		add_action( 'wp_ajax_r2_offload_prune', [ $this, 'prune' ] );
		add_action( 'wp_ajax_r2_offload_prune_start', [ $this, 'prune_start' ] );
		add_action( 'wp_ajax_r2_offload_prune_tick', [ $this, 'prune_tick' ] );
		add_action( 'wp_ajax_r2_offload_prune_stop', [ $this, 'prune_stop' ] );
		add_action( 'wp_ajax_r2_offload_restore', [ $this, 'restore' ] );
		add_action( 'wp_ajax_r2_offload_serve_source', [ $this, 'serve_source' ] );
		add_action( 'wp_ajax_r2_offload_estimate', [ $this, 'estimate' ] );
	}

	public function estimate(): void {
		$this->guard();
		$gb      = isset( $_POST['gb'] ) ? max( 0.0, (float) $_POST['gb'] ) : 0.0;
		$objects = isset( $_POST['objects'] ) ? max( 0, (int) $_POST['objects'] ) : 0;
		$egress  = isset( $_POST['egress'] ) && $_POST['egress'] !== '' ? max( 0.0, (float) $_POST['egress'] ) : null;
		$bytes   = (int) round( $gb * 1073741824 );
		wp_send_json_success(
			[
				'current'   => $this->settings->provider(),
				'estimates' => \R2_Offload\Storage\Cost_Estimator::estimate_all( $bytes, $objects, $egress ),
			]
		);
	}

	public function prune(): void {
		$this->guard();
		@set_time_limit( 120 );
		$dry   = ! empty( $_POST['dry'] );
		$batch = isset( $_POST['batch'] ) ? max( 1, min( 200, (int) $_POST['batch'] ) ) : 25;
		$state = $this->pruner->start( $dry, $batch );
		if ( $state['status'] === 'running' ) {
			$state = $this->pruner->tick( $batch );
		}
		wp_send_json_success( $state );
	}

	public function prune_start(): void {
		$this->guard();
		@set_time_limit( 60 );
		$dry   = ! empty( $_POST['dry'] );
		$batch = isset( $_POST['batch'] ) ? max( 1, min( 200, (int) $_POST['batch'] ) ) : 25;
		wp_send_json_success( $this->pruner->start( $dry, $batch ) );
	}

	public function prune_tick(): void {
		$this->guard();
		@set_time_limit( 120 );
		$batch = isset( $_POST['batch'] ) ? max( 1, min( 200, (int) $_POST['batch'] ) ) : 0;
		wp_send_json_success( $this->pruner->tick( $batch ) );
	}

	public function prune_stop(): void {
		$this->guard();
		wp_send_json_success( $this->pruner->stop() );
	}

	public function restore(): void {
		$this->guard();
		$id = isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0;
		if ( $id <= 0 ) {
			wp_send_json_error( [ 'message' => 'bad id' ], 400 );
		}
		wp_send_json_success( $this->pruner->restore( $id ) );
	}

	public function serve_source(): void {
		$this->guard();
		$src = sanitize_key( (string) ( $_POST['source'] ?? '' ) );
		if ( ! in_array( $src, [ 'local', 'remote' ], true ) ) {
			wp_send_json_error( [ 'message' => 'source must be local|remote' ], 400 );
		}
		$this->settings->update( [ 'rewrite_urls' => $src === 'remote' ? 1 : 0 ] );
		wp_send_json_success( [ 'source' => $src ] );
	}

	public function debug(): void {
		$this->guard();
		wp_send_json_success(
			[
				'counts'      => $this->migrator->debug_counts(),
				'sample'      => $this->migrator->debug_sample( 10 ),
				'control'     => $this->migrator->control(),
				'scan'        => $this->scanner->get_state(),
				'prune'       => $this->pruner->get_state(),
				'vendor_ok'   => \R2_Offload\Installer::vendor_ready(),
				'sdk_class'   => class_exists( '\\Google\\Cloud\\Storage\\StorageClient' ),
				'deps_state'  => \R2_Offload\Installer::state(),
				'log_file'    => R2_OFFLOAD_DIR . \R2_Offload\Logger::FILE,
				'log_tail'    => self::tail_log( 60 ),
			]
		);
	}

	private static function tail_log( int $lines ): array {
		$file = R2_OFFLOAD_DIR . \R2_Offload\Logger::FILE;
		if ( ! file_exists( $file ) ) {
			return [];
		}
		$data = @file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
		if ( ! $data ) {
			return [];
		}
		return array_slice( $data, -$lines );
	}

	private function guard(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( [ 'message' => 'forbidden' ], 403 );
		}
		check_ajax_referer( 'r2_offload_ajax', 'nonce' );
	}

	public function scan_start(): void {
		$this->guard();
		$dry = ! empty( $_POST['dry'] );
		$this->scanner->start( $dry );
		wp_send_json_success( $this->scanner->get_state() );
	}

	public function scan_tick(): void {
		$this->guard();
		$batch = isset( $_POST['batch'] ) ? max( 10, min( 1000, (int) $_POST['batch'] ) ) : 200;
		wp_send_json_success( $this->scanner->scan_chunk( $batch ) );
	}

	public function scan_reset(): void {
		$this->guard();
		$this->scanner->reset_state();
		wp_send_json_success( $this->scanner->get_state() );
	}

	public function migrate(): void {
		$this->guard();
		$op = sanitize_key( (string) ( $_POST['op'] ?? '' ) );
		switch ( $op ) {
			case 'start':
				$this->migrator->start(
					isset( $_POST['batch_size'] ) ? (int) $_POST['batch_size'] : 25,
					isset( $_POST['concurrency'] ) ? (int) $_POST['concurrency'] : 4
				);
				break;
			case 'pause':
				$this->migrator->pause();
				break;
			case 'resume':
				$this->migrator->resume();
				break;
			case 'stop':
				$this->migrator->stop();
				break;
			case 'retry':
				$this->migrator->retry_failed();
				break;
			default:
				wp_send_json_error( [ 'message' => 'unknown op' ], 400 );
		}
		wp_send_json_success( $this->migrator->progress() );
	}

	public function progress(): void {
		$this->guard();
		wp_send_json_success(
			[
				'scan'     => $this->scanner->get_state(),
				'migrate'  => $this->migrator->progress(),
				'prune'    => $this->pruner->get_state(),
			]
		);
	}

	public function verify(): void {
		$this->guard();
		$id = isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0;
		if ( $id <= 0 ) {
			wp_send_json_error( [ 'message' => 'bad id' ], 400 );
		}
		wp_send_json_success( $this->verifier->verify_attachment( $id ) );
	}

	public function migrate_tick(): void {
		$this->guard();
		@set_time_limit( 120 );
		$id = $this->migrator->process_one();
		wp_send_json_success(
			[
				'processed_id' => $id,
				'progress'     => $this->migrator->progress(),
				'failed'       => $this->migrator->failed_items( 50 ),
			]
		);
	}

	public function retry_one(): void {
		$this->guard();
		$id = isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0;
		if ( $id <= 0 ) {
			wp_send_json_error( [ 'message' => 'bad id' ], 400 );
		}
		$this->migrator->retry_single( $id );
		wp_send_json_success( $this->migrator->progress() );
	}

	public function install_deps(): void {
		$this->guard();
		@set_time_limit( 600 );
		wp_send_json_success( \R2_Offload\Installer::install() );
	}
}
