<?php

/**
 * Class BackWPup_Destination_Folder.
 */
class BackWPup_Destination_Folder extends BackWPup_Destinations
{
    public function option_defaults(): array
    {
        $backups_dir = self::getDefaultBackupsDirectory();

        return ['maxbackups' => 15, 'backupdir' => $backups_dir, 'backupsyncnodelete' => true];
    }


    /**
     * {@inheritdoc}
	 */
	public function edit_form_post_save( $jobid ): void {
		$backup_dir = trim( sanitize_text_field( $_POST['backupdir'] ) ); // phpcs:ignore WordPress.Security

        try {
            $backup_dir = trailingslashit(
                BackWPup_File::normalize_path(BackWPup_Path_Fixer::slashify($backup_dir))
            );
        } catch (\InvalidArgumentException $e) {
            $backup_dir = self::getDefaultBackupsDirectory();
        }

		$max_backups    = isset( $_POST['maxbackups'] ) ? absint( $_POST['maxbackups'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
				$jobids = (array) $jobid;
		foreach ( $jobids as $jobid ) {
			BackWPup_Option::update( $jobid, 'backupdir', $backup_dir );
			BackWPup_Option::update( $jobid, 'maxbackups', $max_backups );
			BackWPup_Option::update( $jobid, 'backupsyncnodelete', ! empty( $_POST['backupsyncnodelete'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
		}
	}

    /**
     * {@inheritdoc}
     */
    public function file_delete(string $jobdest, string $backupfile): void
    {
        [$jobid, $dest] = explode('_', $jobdest, 2);

        if (empty($jobid)) {
            return;
        }

        $backup_dir = esc_attr(BackWPup_Option::get((int) $jobid, 'backupdir'));
        $backup_dir = BackWPup_File::get_absolute_path($backup_dir);

        $backupfile = realpath(trailingslashit($backup_dir) . basename($backupfile));

		if ( $backupfile && is_writable( $backupfile ) && ! is_dir( $backupfile ) && ! is_link( $backupfile ) ) { //phpcs:ignore
			wp_delete_file( $backupfile );
		} else {
			// translators: %s: backup file path.
			\BackWPup_Admin::message( sprintf( __( 'Could not delete backup archive "%s", check permissions!', 'backwpup' ), $backupfile ), true );
		}
    }

    /**
     * {@inheritdoc}
	 */
	public function file_get_list( ?string $jobdest = '' ): array {
		$jobid         = 0;
		$backup_folder = $this->option_defaults()['backupdir'];
		if ( '' !== $jobdest ) {
			[$jobid, $dest] = explode( '_', $jobdest, 2 );
			$backup_folder  = BackWPup_Option::get( $jobid, 'backupdir' );
		}

		$filecounter       = 0;
		$files             = [];
		$backup_folder     = BackWPup_File::get_absolute_path( $backup_folder );
		$not_allowed_files = [
            'index.php',
            '.htaccess',
            '.donotbackup',
            'Web.config',
        ];

        if (is_dir($backup_folder)) {
            $dir = $this->get_backwpup_directory($backup_folder);

            foreach ($dir as $file) {
                if (
                    $file->isDot()
                    || $file->isDir()
                    || $file->isLink()
                    || in_array($file->getFilename(), $not_allowed_files, true)
                    || !$this->is_backup_archive($file->getFilename())
                ) {
                    continue;
                }

                if ($file->isReadable()) {
                    //file list for backups
                    $files[$filecounter]['folder'] = $backup_folder;
                    $files[$filecounter]['file'] = str_replace('\\', '/', $file->getPathname());
                    $files[$filecounter]['filename'] = $file->getFilename();
                    $files[$filecounter]['downloadurl'] = add_query_arg(
                        [
                            'page' => 'backwpupbackups',
                            'action' => 'downloadfolder',
                            'file' => $file->getFilename(),
                            'local_file' => $file->getFilename(),
                            'jobid' => $jobid,
                        ],
                        network_admin_url('admin.php')
                    );
                    $files[$filecounter]['filesize'] = $file->getSize();
                    $files[$filecounter]['time'] = $file->getMTime() + (get_option('gmt_offset') * 3600);
                    ++$filecounter;
                }
            }
        }

        return array_filter($files);
    }

    /**
     * {@inheritdoc}
     */
    public function job_run_archive(BackWPup_Job $job_object): bool
    {
        $job_object->substeps_todo = 1;
        if (!empty($job_object->job['jobid'])) {
            BackWPup_Option::update(
                $job_object->job['jobid'],
                'lastbackupdownloadurl',
                add_query_arg(
                    [
                        'page' => 'backwpupbackups',
                        'action' => 'downloadfolder',
                        'file' => basename($job_object->backup_file),
                        'jobid' => $job_object->job['jobid'],
                    ],
                    network_admin_url('admin.php')
                )
            );
        }

        // Delete old Backupfiles.
        $backupfilelist = [];
        $files = [];

        if (is_writable($job_object->backup_folder)) { //make file list
            try {
                $dir = new BackWPup_Directory($job_object->backup_folder);

                foreach ($dir as $file) {
                    if ($file->isDot() || $file->isDir() || $file->isLink() || !$file->isWritable()) {
                        continue;
                    }

                    $is_backup_archive = $this->is_backup_archive($file->getFilename());
                    $is_owned_by_job = $this->is_backup_owned_by_job($file->getFilename(), $job_object->job['jobid']);
                    if ($is_backup_archive && $is_owned_by_job) {
                        $backupfilelist[$file->getMTime()] = clone $file;
                    }
                }
            } catch (UnexpectedValueException $e) {
                $job_object->log(
                    sprintf(
                        esc_html__('Could not open path: %s', 'backwpup'),
                        $e->getMessage()
                    ),
                    E_USER_WARNING
                );
            }
        }

        if ($job_object->job['maxbackups'] > 0) {
            if (count($backupfilelist) > $job_object->job['maxbackups']) {
                ksort($backupfilelist);
				$numdeltefiles = 0;
				$deleted_files = [];

                while ($file = array_shift($backupfilelist)) {
                    if (count($backupfilelist) < $job_object->job['maxbackups']) {
                        break;
					}
					wp_delete_file( $file->getPathname() );
					$deleted_files[] = $file->getPathname();
					foreach ( $files as $key => $filedata ) {
						if ( $filedata['file'] === $file->getPathname() ) {
							unset( $files[ $key ] );
						}
                    }
                    ++$numdeltefiles;
                }

                if ($numdeltefiles > 0) {
                    $job_object->log(
                        sprintf(
                            _n('One backup file deleted', '%d backup files deleted', $numdeltefiles, 'backwpup'),
                            $numdeltefiles
                        ),
                        E_USER_NOTICE
                    );
				}

				parent::remove_file_history_from_database( $deleted_files, 'FOLDER' );
			}
        }

        ++$job_object->substeps_done;

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function can_run(array $job_settings): bool
    {
        return !(empty($job_settings['backupdir']) || $job_settings['backupdir'] == '/');
    }

    /**
     * Returns new instance of BackWPup_Directory.
     *
     * @param string $dir the directory to iterate
     */
    protected function get_backwpup_directory(string $dir): BackWPup_Directory
    {
        return new BackWPup_Directory($dir);
    }

    private static function getDefaultBackupsDirectory()
    {
        $upload_dir = wp_upload_dir(null, false, true);
        $backups_dir = trailingslashit(
            str_replace(
                '\\',
                '/',
                $upload_dir['basedir']
            )
        ) . 'backwpup/' . BackWPup::get_plugin_data('hash') . '/backups/';
        $content_path = trailingslashit(BackWPup_Path_Fixer::slashify((string) WP_CONTENT_DIR));

        return str_replace($content_path, '', $backups_dir);
    }
}
