<?php

namespace CleantalkSP\SpbctWP\Scanner;

class Cure
{
    public $signature = null;
    public $objects = array();

    /**
     * @var array
     * @psalm-suppress PossiblyUnusedProperty
     */
    public $actions = array();

    /**
     * @var array
     * @psalm-suppress PossiblyUnusedProperty
     */
    public $modifiers = array();

    /**
     * @var array
     * @psalm-suppress PossiblyUnusedProperty
     */
    public $comments = array();

    public $result = true;

    public function __construct($file)
    {
        global $wpdb;

        $weak_spots = json_decode($file['weak_spots'], true);

        if ( ! empty($weak_spots['SIGNATURES']) ) {
            foreach ( $weak_spots['SIGNATURES'] as $_string => $signatures_in_string ) {
                foreach ( $signatures_in_string as $signature_id ) {
                    $tmp             = $wpdb->get_results(
                        'SELECT * FROM ' . SPBC_TBL_SCAN_SIGNATURES . ' WHERE id = "' . $signature_id . '"',
                        OBJECT
                    );
                    $this->signature = $tmp[0];

                    $result = $this->signatureCure($file, $this->signature);
                    if ( ! empty($result['error']) ) {
                        $this->result = $result;
                        return;
                    }
                }
            }
        } else {
            $this->result = array('error' => 'COULD NOT GET SIGNATURE FROM DB');
        }
    }

    public function signatureCure($file, $signature)
    {
        global $spbc;

        if ( ! empty($signature->cci) ) {
            $instructions = json_decode($signature->cci, true);

            foreach ( $instructions['cci'] as $instruction ) {
                // Object
                foreach ( $instruction['objects'] as $_key => &$object ) {
                    // Building path to file

                    // Default if unset
                    if ( ! isset($object['file']) ) {
                        $object['file'] = 'self';
                    }

                    // self
                    if ( $object['file'] === 'self' ) {
                        $object['file'] = spbc_get_root_path() . $file['path'];
                        // absolute "/var/www/wordpress.com"
                    } elseif ( $object['file'][0] == '/' || $object['file'][0] == '\\' ) {
                        $object['file'] = spbc_get_root_path() . $object['file'];
                        // relative ".some_file.php"
                    } else {
                        $object['file'] = spbc_get_root_path()
                                          . preg_replace('/(.*\\\\).*?\.php$/', '$1', $file['path'])
                                          . $object['file'];
                    }

                    // Building code if nessary
                    if ( isset($object['code']) ) {
                        if ( $object['code'] === 'self' ) {
                            $object['code'] = $signature->body;
                        }
                    }

                    // Perform actions
                    if ( ! isset($object['code']) ) {
                        $result = $this->actionPerformWithFile(
                            $object,
                            $instruction['action'],
                            $file,
                            $signature->id
                        ); // Actions with file.
                    } else {
                        $result = $this->actionPerformWithCode(
                            $object,
                            $instruction['action'],
                            $file,
                            $signature->id
                        ); // Actions with code.
                    }

                    $this->objects[] = $object;

                    if ( ! empty($result['error']) ) {
                        return $result;
                    }

                    if ( ! $spbc->settings['there_was_signature_treatment'] ) {
                        $spbc->settings['there_was_signature_treatment'] = 1;
                        $spbc->save('settings');
                    }
                }
            }
        }
    }

    /**
     * @param $object
     * @param $actions
     * @param $file
     * @param string $signature_id
     *
     * @return array|bool|bool[]|false|int|string[]
     */
    public function actionPerformWithFile($object, $actions, $file, $signature_id)
    {
        global $spbc;

        $result = true;

        if ( ! file_exists($object['file']) ) {
            return array('error' => 'File does not exists.');
        }

        foreach ( $actions as $action => $action_details ) {
            switch ( $action ) {
                case 'delete':
                    $result = unlink($object['file']);
                    file_put_contents(
                        $object['file'],
                        "<?php\n// " . $spbc->data["wl_brandname"] . ": Malware was deleted: #" . $signature_id
                    );
                    break;
                case 'quarantine':
                    $result = spbc_scanner_file_quarantine(true, $file['fast_hash']);
                    break;
                case 'move_to':
                    /** @todo moveTo */
                    break;
                case 'replace_with':
                    if ( $action_details === 'original' ) {
                        $result = spbc_scanner_file_replace(true, $file['fast_hash']);
                    }
                    if ( $action_details === 'blank' ) {
                        $result = file_put_contents(
                            $object['file'],
                            '<?php\n/* File was cleaned by ' . $spbc->data["wl_brandname"] . ' */'
                        );
                    }
                    break;
            }
        }

        return $result;
    }

    /**
     * @param $object
     * @param $actions
     * @param $file
     * @param $signature_id
     *
     * @return array|bool|int
     */
    public function actionPerformWithCode($object, $actions, $_file, $signature_id)
    {
        global $spbc;

        $result = true;

        try {
            foreach ( $actions as $action => $action_details ) {
                if ( file_exists($object['file']) ) {
                    $file_content = file_get_contents($object['file']);
                } else {
                    return array('error' => 'File does not exists.');
                }

                $is_regexp = \CleantalkSP\SpbctWP\Helpers\Helper::isRegexp($object['code']);

                switch ( $action ) {
                    case 'delete':
                        $file_content = $is_regexp
                            ? preg_replace(
                                $object['code'],
                                '// ' . $spbc->data["wl_brandname"] . ': Malware was deleted: #' . $signature_id,
                                $file_content,
                                1
                            )
                            : str_replace(
                                $object['code'],
                                '// ' . $spbc->data["wl_brandname"] . ': Malware was deleted: #' . $signature_id,
                                $file_content
                            );

                        $result = @file_put_contents($object['file'], $file_content);

                        break;

                    case 'replace_with':
                        $file_content = $is_regexp
                            ? preg_replace($object['code'], $action_details, $file_content, 1)
                            : str_replace($object['code'], $action_details, $file_content);

                        $result = @file_put_contents($object['file'], $file_content);

                        break;
                }
            }

            if ( false === $result ) {
                $result = array('error' => 'Permissions denied.');
            }
        } catch (\Exception $e) {
            $result = array('error' => 'Something went wrong during cure: ' . $e->getMessage());
        }
        return $result;
    }

    public static function cureSelectedAction()
    {
        spbc_check_ajax_referer('spbc_secret_nonce', 'security');

        if (empty($_POST['selectedIds'])) {
            wp_send_json_error(esc_html__('No items for checking', 'security-malware-firewall'));
        }

        foreach ($_POST['selectedIds'] as $id) {
            $id = sanitize_user($id, true);
            $result = spbc_cure_file($id);

            if (is_wp_error($result)) {
                wp_send_json_error($result->get_error_message());
            }

            wp_send_json_success($result);
        }
    }

    public static function cureAll($ids)
    {
        foreach ($ids as $id) {
            $id = sanitize_user($id, true);
            $result = spbc_cure_file($id);

            if (is_wp_error($result)) {
                return array('error' => $result->get_error_message());
            }
        }

        return 'OK';
    }
}
