<?php

namespace WP_Defender\Behavior\Scan;

use Calotes\Component\Behavior;
use WP_Defender\Behavior\WPMUDEV;
use WP_Defender\Model\Scan;
use WP_Defender\Model\Scan_Item;
use WP_Defender\Traits\IO;
use WP_Defender\Traits\Plugin;
use WP_Defender\Traits\Theme;

class Known_Vulnerability extends Behavior {
	use IO, Plugin, Theme;

	public function vuln_check() {
		$this->attach_behavior( WPMUDEV::class, WPMUDEV::class );
		global $wp_version;
		$info_cached = [];
		$data        = [
			'plugins'   => json_encode( $this->gather_fact_plugins( $info_cached ) ),
			'themes'    => json_encode( $this->gather_fact_themes( $info_cached ) ),
			'wordpress' => $wp_version
		];

		$ret = $this->make_check( $data );
		if ( is_wp_error( $ret ) ) {
			$this->log( $ret->get_error_message() );

			$this->owner->scan->status = Scan::STATUS_ERROR;
			$this->owner->scan->save();

			return true;
		}

		$this->process_result( $ret['plugins'], $info_cached, 'plugin' );
		$this->process_result( $ret['themes'], $info_cached, 'theme' );
		$this->process_result( $ret['wordpress'], [], 'wordpress' );
		$this->owner->scan->calculate_percent( 100, 5 );

		$last = Scan::get_last();
		if ( is_object( $last ) ) {
			$ignored_issues = $last->get_issues( Scan_Item::TYPE_VULNERABILITY, Scan_Item::STATUS_IGNORE );
			foreach ( $ignored_issues as $issue ) {
				$this->owner->scan->add_item( Scan_Item::TYPE_VULNERABILITY, $issue->raw_data, Scan_Item::STATUS_IGNORE );
			}
		}

		return true;

	}

	/**
	 * @param $data
	 *
	 * @return mixed
	 */
	public function make_check( $data ) {
		$ret = $this->make_wpmu_request( WPMUDEV::API_SCAN_KNOWN_VULN, $data, [
			'method' => 'POST'
		] );

		return $ret;
	}

	/**
	 * @param $result
	 * @param $info
	 * @param $type
	 */
	private function process_result( $result, $info, $type ) {
		if ( empty( $result ) ) {
			return;
		}
		$this->log( sprintf( 'Checking %s', $type ) );
		$model = $this->owner->scan;

		foreach ( $result as $base_slug => $bugs ) {
			list( $name, $current_version, $slug ) = $info[ $base_slug ];
			$raw_data = [
				'type'      => $type,
				'slug'      => $slug,
				'base_slug' => $base_slug,
				'version'   => $current_version,
				'name'      => $name,
				'bugs'      => []
			];
			if ( count( $bugs['confirmed'] ) ) {
				$this->log( sprintf( '%s has %d known bugs', $slug, count( $bugs['confirmed'] ) ) );
				foreach ( (array) $bugs['confirmed'] as $bug ) {
					if ( version_compare( $current_version, $bug['fixed_in'], '<' ) ) {
						$raw_data['bugs'][] = [
							'vuln_type' => $bug['vuln_type'],
							'title'     => $bug['title'],
							'ref'       => $bug['references'],
							'fixed_in'  => $bug['fixed_in'],
						];
					}
				}

				$model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
			}
		}
	}

	/**
	 * Get all the plugins install on this site, no matter the plugin status
	 *
	 * @param $info_cached
	 *
	 * @return mixed
	 */
	private function gather_fact_plugins( &$info_cached ) {
		$model = Scan::get_last();
		foreach ( $this->get_plugins() as $slug => $plugin ) {
			if ( is_object( $model ) && $model->is_issue_ignored( $slug ) ) {
				continue;
			}
			$base_slug                 = explode( '/', $slug ); //DIRECTORY_SEPARATOR wont work on windows
			$base_slug                 = array_shift( $base_slug );
			$plugins[ $base_slug ]     = $plugin['Version'];
			$info_cached[ $base_slug ] = [ $plugin['Name'], $plugin['Version'], $slug ];
		}

		return $plugins;
	}

	/**
	 * @return mixed
	 */
	private function gather_fact_themes( &$info_cached ) {
		$model = Scan::get_last();
		foreach ( $this->get_themes() as $theme ) {
			if ( is_object( $theme->parent() ) ) {
				continue;
			}
			if ( is_object( $model ) && $model->is_issue_ignored( $theme->get_template() ) ) {
				continue;
			}
			$themes[ $theme->get_template() ]      = $theme->Version;
			$info_cached[ $theme->get_template() ] = [ $theme->Name, $theme->Version, $theme->get_template() ];
		}

		return $themes;
	}
}