<?php

namespace CleantalkSP\SpbctWP\Scanner\ScannerActions;

use CleantalkSP\SpbctWP\Helpers\HTTP;
use CleantalkSP\SpbctWP\Scanner\Helper;

class QuarantineActions
{
    /**
     * tested
     * Replacing error codes by readable and translatable format.
     * We have to add new error descriptions here future.
     *
     * @param $output_array
     *
     * @return array
     */
    public static function makeQuarantineResultHumanReadable($output_array)
    {
        if (is_array($output_array) && array_key_exists('error', $output_array)) {
            $errors_codes = array(
                'WEBSITE_RESPONSE_BAD',
                'REVERT_OK'
            );
            $errors_texts = array(
                esc_html__('The requested action caused a website error.', 'security-malware-firewall'),
                // WEBSITE_RESPONSE_BAD
                esc_html__('The changes were reverted.', 'security-malware-firewall'),
                // REVERT_OK
            );
            foreach ($output_array as $key => $item) {
                $output_array[ $key ] = str_replace($errors_codes, $errors_texts, $item);
            }
        }

        return $output_array;
    }

    /**
     * Restore file from quarantine
     * @param string $file_id
     * @return array
     */
    public static function restoreFromQuarantine($file_id)
    {
        global $wpdb;

        if (!$file_id) {
            return array('error' => 'WRONG_FILE_ID');
        }

        // Getting file info.
        $sql = $wpdb->prepare('SELECT *
        FROM ' . SPBC_TBL_SCAN_FILES . '
        WHERE fast_hash = %s
        LIMIT 1', $file_id);
        $sql_result = $wpdb->get_results($sql, ARRAY_A);
        $file_info  = isset($sql_result[0]) ? $sql_result[0] : null;

        if (empty($file_info)) {
            return array('error' => 'FILE_NOT_FOUND');
        }

        if (empty($file_info['q_path']) ||
            !is_string($file_info['q_path']) ||
            !file_exists($file_info['q_path'])
        ) {
            return array('error' => 'FILE_NOT_EXISTS');
        }

        if (!is_writable($file_info['q_path'])) {
            return array('error' => 'FILE_NOT_WRITABLE');
        }

        if (!copy($file_info['q_path'], spbc_get_root_path() . $file_info['path'])) {
            return array('error' => 'COPY_FAILED');
        }

        $previous = json_decode($file_info['previous_state'], true);

        $result = $wpdb->update(
            SPBC_TBL_SCAN_FILES,
            array(
                'status' => $previous['status'],
                'q_path' => null,
                'q_time' => null,
            ),
            array('fast_hash' => $file_info['fast_hash']),
            array('%s', '%s', '%d',),
            array('%s')
        );

        if ($result === false || $result <= 0) {
            return array('error' => 'UPDATE_TABLE_FAILED');
        }

        if (!unlink($file_info['q_path'])) {
            return array('error' => 'DELETE_FAILED');
        }

        return array('success' => true,);
    }

    /**
     * Delete the quarantined copy of a file.
     * Operates on the quarantine storage only, the live website files are not touched.
     * @param string $file_id
     * @return array
     */
    public static function deleteFromQuarantine($file_id)
    {
        global $wpdb;

        if (!$file_id) {
            return array('error' => 'WRONG_FILE_ID');
        }

        // Getting file info.
        $sql = $wpdb->prepare('SELECT *
        FROM ' . SPBC_TBL_SCAN_FILES . '
        WHERE fast_hash = %s
        LIMIT 1', $file_id);
        $sql_result = $wpdb->get_results($sql, ARRAY_A);
        $file_info  = isset($sql_result[0]) ? $sql_result[0] : null;

        if (empty($file_info)) {
            return array('error' => 'FILE_NOT_FOUND');
        }

        if ($file_info['status'] !== 'QUARANTINED') {
            return array('error' => 'FILE_NOT_QUARANTINED');
        }

        if (empty($file_info['q_path']) ||
            !is_string($file_info['q_path']) ||
            !file_exists($file_info['q_path'])
        ) {
            return array('error' => 'FILE_NOT_EXISTS');
        }

        $q_dir = dirname($file_info['q_path']);
        if (!is_dir($q_dir) || !is_writable($q_dir)) {
            return array('error' => 'FILE_NOT_WRITABLE');
        }

        if (!unlink($file_info['q_path'])) {
            return array('error' => 'DELETE_FAILED');
        }

        // Deleting row from DB
        $result = $wpdb->delete(SPBC_TBL_SCAN_FILES, array('fast_hash' => $file_info['fast_hash']));
        if ($result === false) {
            return array('error' => 'DB_COULDNT_DELETE_ROW');
        }

        return array('success' => true);
    }

    /**
     * doQuarantineFile
     * Quarantine file
     * @param string $file_id
     * @return array
     */
    public static function doQuarantineFile($file_id)
    {
        global $wpdb;

        $root_path = spbc_get_root_path();

        if (!$file_id) {
            return array('error' => 'WRONG_FILE_ID');
        }

        // Getting file info.
        $sql = $wpdb->prepare('SELECT *
        FROM ' . SPBC_TBL_SCAN_FILES . '
        WHERE fast_hash = %s
        LIMIT 1', $file_id);
        $sql_result = $wpdb->get_results($sql, ARRAY_A);
        $file_info  = isset($sql_result[0]) ? $sql_result[0] : null;

        if (empty($file_info)) {
            return array('error' => 'FILE_NOT_FOUND');
        }

        if (Helper::isWpConfigPath($file_info['path'])) {
            return array('error' => Helper::getWpConfigManualCleanupMessage());
        }

        if (!file_exists($root_path . $file_info['path'])) {
            return array('error' => 'FILE_NOT_EXISTS');
        }

        if (!is_writable($root_path . $file_info['path'])) {
            return array('error' => 'FILE_NOT_WRITABLE');
        }

        $q_path = SPBC_PLUGIN_DIR . 'quarantine/'
                    . str_replace('/', '__', str_replace('\\', '__', $file_info['path'])) . '___'
                    . md5($file_info['path'] . rand(0, 99999999)) . '.punished';

        $dir_name = SPBC_PLUGIN_DIR . 'quarantine/';
        if ( ! is_dir($dir_name)) {
            mkdir($dir_name);
            file_put_contents($dir_name . 'index.php', '<?php');
        }

        if (!copy($root_path . $file_info['path'], $q_path)) {
            return array('error' => 'COPY_FAILED');
        }

        $result = $wpdb->update(
            SPBC_TBL_SCAN_FILES,
            array(
                'status'         => 'QUARANTINED',
                'q_path'         => $q_path,
                //should be offset to use in date()
                'q_time'         => current_time('timestamp'),
                'previous_state' => json_encode(array(
                                                    'status' => $file_info['status'],
                                                )),
            ),
            array('full_hash' => $file_info['full_hash'], 'fast_hash' => $file_info['fast_hash']),
            array('%s', '%s', '%d', '%s'),
            array('%s', '%s')
        );

        if ($result === false || $result <= 0) {
            return array('error' => 'UPDATE_TABLE_FAILED');
        }

        if (!unlink($root_path . $file_info['path'])) {
            return array('error' => 'DELETE_FAILED');
        }

        $response_content       = HTTP::getContentFromURL(get_option('home'));
        if ( isset($response_content['error']) || spbc_search_page_errors($response_content) ) {
            $result_of_revert = self::restoreFromQuarantine($file_info['fast_hash']);
            $error_of_revert = ! empty($result_of_revert['error'])
                ? ' REVERT_FAILED ' . $result_of_revert['error']
                : ' REVERT_OK';
            return array('error' => 'WEBSITE_RESPONSE_BAD' . $error_of_revert);
        }

        return array('success' => true);
    }

    /**
     * Remove file from quarantine list
     * @param string $file_id
     * @return void
     */
    public static function removeFileFromQuarantineList($file_id)
    {
        global $wpdb;

        $wpdb->delete(SPBC_TBL_SCAN_FILES, array('fast_hash' => $file_id));
    }
}
