<?php

namespace CleantalkSP\SpbctWP\Scanner;

use CleantalkSP\SpbctWP\Helpers\CSV;
use CleantalkSP\SpbctWP\Helpers\HTTP;
use CleantalkSP\SpbctWP\Scanner\ScannerActions\LinksActions;

class Helper
{
    /**
     * Getting real hashs of CMS core files
     *
     * @param string $cms CMS name
     * @param string $version CMS version
     *
     * @return array Array with all CMS files hashes or Error Array
     */
    public static function getHashesForCMS($cms, $version)
    {
        $file_path = 'https://cleantalk-security.s3.amazonaws.com/cms_checksums/' . $cms . '/' . $version . '/' . $cms . '_' . $version . '.json.gz';

        if ( HTTP::getResponseCode($file_path) === 200 ) {
            $gz_data = HTTP::getContentFromURL($file_path, false);

            if ( empty($gz_data['error']) ) {
                if ( function_exists('gzdecode') ) {
                    $data = gzdecode($gz_data);

                    if ( $data !== false ) {
                        $result = json_decode($data, true);
                        $result = $result['data'];

                        if ( count($result['checksums']) === (int)$result['checksums_count'] ) {
                            return $result;
                        }

                        return array('error' => 'FILE_DOESNT_MATHCES');
                    }

                    return array('error' => 'COULDNT_UNPACK');
                }

                return array('error' => 'Function gzdecode not exists. Please update your PHP to version 5.4');
            }

            return (array) $gz_data;
        }

        return array('error' => 'Remote file not found or WordPress version is not supported. Yo could try again later (few hours). Contact tech support if it repeats.');
    }

    /**
     * Getting real hashs of plugin's or theme's files
     *
     * @param string $cms CMS name
     * @param string $type Plugin type (plugin|theme)
     * @param string $plugin Plugin name
     * @param string $version Plugin version
     *
     * @return array Array with all CMS files hashes or Error Array
     */
    public static function getHashesForModules($cms, $type, $plugin, $version)
    {
        $file_path = 'https://cleantalk-security.s3.amazonaws.com/extensions_checksums/' . $cms . '/' . $type . 's/' . $plugin . '/' . $version . '.csv.gz';

        if ( HTTP::getResponseCode($file_path) === 200 ) {
            $gz_data = HTTP::getContentFromURL($file_path, false);

            if ( empty($gz_data['error']) ) {
                if ( function_exists('gzdecode') ) {
                    $data = gzdecode($gz_data);

                    if ( $data !== false ) {
                        $lines = CSV::parseCSV($data);

                        if ( count($lines) > 0 ) {
                            $result = array();

                            foreach ( $lines as $hash_info ) {
                                if ( empty($hash_info) ) {
                                    continue;
                                }

                                preg_match('/.*\.(\S*)$/', $hash_info[0], $matches);
                                $ext = isset($matches[1]) ? $matches[1] : '';
                                if ( ! in_array($ext, array('php', 'html', 'js')) ) {
                                    continue;
                                }

                                $result[] = $hash_info;
                            }

                            if ( count($result) ) {
                                return $result;
                            }

                            return array('error' => 'BAD_HASHES_FILE__PLUG');
                        }

                        return array('error' => 'Empty hashes file');
                    }

                    return array('error' => 'COULDNT_UNPACK');
                }

                return array('error' => 'Function gzdecode not exists. Please update your PHP to version 5.4');
            }

            return (array) $gz_data;
        }

        return array('error' => 'REMOTE_FILE_NOT_FOUND_OR_VERSION_IS_NOT_SUPPORTED__PLUG');
    }

    /**
     * Getting real hashs of approved files
     *
     * @param string $cms CMS name
     * @param string $type Type - approved/rejected
     * @param string $version
     *
     * @return false|string[]|non-empty-array<array-key, string> Array with all files hashes or Error Array
     */
    public static function getHashesForFiles($cms, $type, $version)
    {
        $file_path = 'https://cleantalk-security.s3-us-west-2.amazonaws.com/extensions_checksums/' . $cms . '/' . $type . '/' . $version . '.csv.gz';
        if ( HTTP::getResponseCode($file_path) !== 200 ) {
            return array('error' => 'REMOTE_FILE_NOT_FOUND');
        }

        $gz_data = HTTP::getContentFromURL($file_path, false);
        if ( !empty($gz_data['error']) ) {
            return (array) $gz_data;
        }

        if ( !function_exists('gzdecode') ) {
            return array('error' => 'Function gzdecode not exists. Please update your PHP to version 5.4');
        }

        $data = gzdecode($gz_data);
        if ( $data === false ) {
            return array('error' => 'COULDNT_UNPACK');
        }

        /** @psalm-suppress UndefinedMethod */
        $lines = CSV::parseCSVLite($data);
        if ( count($lines) < 1 ) {
            return array('error' => 'Empty hashes file');
        }

        return $lines;
    }

    /**
     * Get original file's content
     *
     * @param array $file_info Array with files data (path, real_full_hash, source_type, source), other is optional
     *
     * @return string|array
     */
    public static function getOriginalFile($file_info)
    {
        $file_info['path'] = str_replace(
            '\\',
            '/',
            $file_info['path']
        ); // Replacing win slashes to Orthodox slashes - in case of Windows

        switch ( $file_info['source_type'] ) {
            case 'PLUGIN':
                $file_info['path'] = preg_replace('@/wp-content/plugins/.*?/(.*)$@i', '$1', $file_info['path']);
                $url_path          = 'https://plugins.svn.wordpress.org/' . $file_info['source'] . '/tags/' . $file_info['version'] . '/' . $file_info['path'];
                break;
            case 'THEME':
                $file_info['path'] = preg_replace('@/wp-content/themes/.*?/(.*)$@i', '$1', $file_info['path']);
                $url_path          = 'https://themes.svn.wordpress.org/' . $file_info['source'] . '/' . $file_info['version'] . '/' . $file_info['path'];
                break;
            default:
                $url_path = 'http://cleantalk-security.s3.amazonaws.com/cms_sources/' . $file_info['source'] . '/' . $file_info['version'] . $file_info['path'];
                break;
        }

        $page_content = HTTP::getContentFromURL($url_path);

        /** @psalm-suppress TypeDoesNotContainType */
        return empty($page_content['error'])
            ? $page_content
            : array('error' => "Couldn't get an original file: " . $page_content['error']);
    }

    public static function clearScannerResults()
    {
        global $spbc;

        $spbc->plugins = array();
        $spbc->save('plugins');

        $spbc->themes = array();
        $spbc->save('themes');

        $spbc->data['scanner'] = array(
            'last_wp_version' => null,
            'cron'            => array(
                'state'         => 'get_hashes',
                'total_scanned' => 0,
                'offset'        => 0,
            ),
        );
        $spbc->save('data');

        $out = [
            'deleted_files_entries'    => Controller::resetCheckResult(),
            'deleted_frontend_entries' => Frontend::resetCheckResult(),
            'deleted_links'            => LinksActions::resetCheckResult(),
        ];
        return $out;
    }

    /**
     * tested
     * Get JSON string of accordion row actions that do not need to be confirmed.
     * @return string
     */
    public static function getRowActionsNeedsNoConfirm()
    {
        global $spbc;
        // by defaults
        $actions = array (
            'defaults' => array(
                'copy_file_info',
                'check_analysis_status',
            ),
            'restricted' => array(),
        );
        // if license is trial
        if ($spbc->data['license_trial']) {
            $actions['restricted'][] = 'delete';
            $actions['restricted'][] = 'quarantine';
            $actions['restricted'][] = 'approve';
        }

        $actions['any'] = array_merge($actions['restricted'], $actions['defaults']);

        $actions = json_encode($actions);
        return is_string($actions) ? $actions : '{[]}';
    }

    /**
     * query
     * Get SQL *WHERE* suffix for SELECT query depends on files category.
     * @param string $category Category of files category which needs to be searched for
     * @return string SQL *WHERE* suffix.
     */
    public static function getSQLWhereAddictionForTableOfCategory($category)
    {
        global $spbc;

        switch ($category) {
            case 'critical':
                $res = ' WHERE status IN ("DENIED_BY_CLOUD", "DENIED_BY_CT")
            OR (
                severity = "CRITICAL"
                AND (
                    status <> "QUARANTINED" AND 
                    status <> "APPROVED_BY_USER" AND 
                    status <> "APPROVED_BY_CT" AND
                    status <> "OK"
                    )
                AND (
                    last_sent IS NULL OR 
                    pscan_status = "DANGEROUS"
                )
            )';
                break;
            case 'suspicious':
                $res = ' WHERE severity <> "CRITICAL" AND
                        last_sent IS NULL AND
                        (status = "MODIFIED" AND source_type IS NOT NULL) 
                        OR (status = "INFECTED" AND severity = "SUSPICIOUS" AND last_sent IS NULL)';
                break;
            case 'approved':
                $res = ' WHERE status = "APPROVED_BY_USER" AND source_type IS NULL';
                break;
            case 'approved_by_cloud':
                $res = ' WHERE ( status = "APPROVED_BY_CT" OR status = "APPROVED_BY_CLOUD") AND source_type IS NULL';
                break;
            case 'analysis_log':
                $res = ' WHERE last_sent IS NOT NULL';
                break;
            case 'unknown':
                $res = ' WHERE status NOT IN ("APPROVED_BY_USER","APPROVED_BY_CT","APPROVED_BY_CLOUD","DENIED_BY_CT","ERROR") AND
						    detected_at >= ' . (time() - $spbc->settings['scanner__list_unknown__older_than'] * 86400) . ' AND
						    source IS NULL AND
						    source_type IS NULL AND
						    size > 0 AND
		                    path NOT LIKE "%wp-content%themes%" AND
                            path NOT LIKE "%wp-content%plugins%" AND
                            path NOT LIKE "%wp-content%cache%" AND
                            path NOT LIKE "%wp-config.php" AND
						    (severity IS NULL OR severity NOT IN ("CRITICAL", "SUSPICIOUS")) AND
						    last_sent IS NULL AND
						    fast_hash NOT IN (SELECT fast_hash FROM ' . SPBC_TBL_CURE_LOG . ' WHERE cure_status = 1)';
                break;
            case 'quarantined':
                $res = ' WHERE status = "QUARANTINED"';
                break;
            case 'frontend_malware':
                $res = ' WHERE approved IS NULL OR approved <> 1';
                break;
            case 'frontend_scan_results_approved':
                $res = ' WHERE approved = 1';
                break;
            case 'skipped':
                $res = ' WHERE status = "ERROR" AND error_msg IS NOT NULL AND error_msg NOT LIKE "%FILE_SIZE_ZERO%"';
                break;
            default:
                $res = '';
        }

        return $res;
    }
}
