<?php

namespace JetBackup\Restore;

use Exception;
use JetBackup\Cron\Task\Task;
use JetBackup\Exception\ExecutionTimeException;
use JetBackup\Exception\RestoreException;
use JetBackup\Factory;
use JetBackup\IO\Lock;
use JetBackup\JetBackup;
use JetBackup\Queue\Queue;
use JetBackup\Queue\QueueItem;
use JetBackup\Wordpress\Wordpress;
use Throwable;

if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');

class Restore {

	const ACTION_RESTORE = 'restore';
	const ACTION_STATUS = 'status';
	const ACTION_CANCEL = 'cancel';
	const ACTION_COMPLETED = 'completed';

	private QueueItem $_queue;
	private Task $_task;
	
	public function __construct(QueueItem $queueItem) {
		$this->_queue = $queueItem;
		$this->_task = new \JetBackup\Cron\Task\Restore();
		$this->_task->setQueueItem($queueItem);
		$this->_task->setExecutionTimeLimit(30);
		$this->_task->setExecutionTimeDie(false);
	}
	
	public function execute($action) {
		switch ($action) {
			case self::ACTION_CANCEL: $this->_actionCancel();
			case self::ACTION_COMPLETED: $this->_actionCompleted();
			case self::ACTION_STATUS: $this->_actionStatus();
			case self::ACTION_RESTORE: $this->_actionRestore();
		}
	}

	private static function _getRestorePath() : string {
		return Factory::getSettingsRestore()->isRestoreAlternatePathEnabled() ? WP_ROOT . JetBackup::SEP . JetBackup::CRON_PUBLIC_URL : WP_ROOT;
	}

	private static function _getRestoreFileName(): string {
		if (!isset($_SERVER['SCRIPT_FILENAME'])) return '';
		$script = Wordpress::getUnslash($_SERVER['SCRIPT_FILENAME']);
		$script = Wordpress::sanitizeTextField($script);
		return basename($script);
	}


	private static function _getRestoreFile() : string {
		return self::_getRestorePath() . JetBackup::SEP . self::_getRestoreFileName();
	}

	private static function _getLockFile() : string {
		return self::_getRestoreFile() . '.lock';
	}

	private function _actionRestore() {

		if (!Lock::LockFile(self::_getLockFile())) {
			self::_output(true, 'Already running...', [
				'status'     => $this->_queue->getStatus(),
			]);
		}
		
		if($this->_queue->getStatus() < Queue::STATUS_DONE) {
			try {
				$this->_task->execute();
			} catch(ExecutionTimeException $e) {
				self::_output(true, 'Execution time reached', [ 'status' => $this->_queue->getStatus() ]);
			} catch(Exception $e) {
				self::_output(false, "Error: " . $e->getMessage());
			} catch(Throwable $e) {
				self::_output(false, "Fatal Error: " . $e->getMessage() . "\nTrace:\n" . $e->getTraceAsString());
			}
		}

		self::_output(true, 'Completed', [ 
			'status'     => $this->_queue->getStatus(), 
		]);
	}

	private static function _selfDelete() {
		@unlink(self::_getRestoreFile());
		@unlink(self::_getLockFile());
	}
	
	private function _actionCompleted() {
		
		if($this->_queue->getStatus() < Queue::STATUS_DONE)
			self::_output(false, 'Restore haven\'t completed yet');

		self::_selfDelete();

		self::_output(true, 'Completed Successfully');
	}
	
	private function _actionCancel() {
		
		$this->_queue->updateStatus(Queue::STATUS_ABORTED);
		$this->_queue->updateProgress('Restore aborted by the user', QueueItem::PROGRESS_LAST_STEP);

		self::_selfDelete();

		self::_output(true, 'Cancelled Successfully');
	}
	
	private function _actionStatus() {

		$log_entries = [];
		$log_file = $this->_task->getLogFile();
		if(file_exists($log_file)) $log_entries = file($log_file);

		$progress = $this->_queue->getProgress();
		
		self::_output(true, '', [
			'status'        => $this->_queue->getStatus(),
			'progress'		=> $progress->getDisplay(),
			'log_entries'	=> $log_entries,
		]);
	}
	
	private static function _output($success, $message, $data=[]) {
		die(json_encode([
			'success'       => $success ? 1 : 0,
			'message'       => $message,
			'data'          => $data,
		]));
	}

}