<?php

if(!defined('SOFTACULOUS')){
	die('Hacking Attempt');
}

class AIWPToolHelpers {

	private $siteurl;
	private $rest_nonce;
	private $cookie_header;

	public function __construct($siteurl, $rest_nonce, $raw_cookie_header){
		$this->siteurl = rtrim($siteurl, '/');
		$this->rest_nonce = $rest_nonce;
		$this->cookie_header = $raw_cookie_header;
	}

	private function request($method, $endpoint, $body = null){
		$url = $this->siteurl . '/wp-json/wp/v2/' . ltrim($endpoint, '/');

		if($method === 'GET' && is_array($body) && !empty($body)){
			$url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($body);
			$body = null;
		}

		$ch = curl_init($url);

		$headers = array(
			'X-WP-Nonce: ' . $this->rest_nonce,
			'Cookie: ' . $this->cookie_header,
		);

		$curl_opts = array(
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_TIMEOUT => 30,
			CURLOPT_SSL_VERIFYPEER => false,
			CURLOPT_HTTPHEADER => $headers,
		);

		if(in_array(strtoupper($method), array('POST', 'PUT', 'PATCH'), true)){
			$headers[] = 'Content-Type: application/json';
			$curl_opts[CURLOPT_HTTPHEADER] = $headers;
			$curl_opts[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
			if(is_array($body)){
				$curl_opts[CURLOPT_POSTFIELDS] = json_encode($body);
			}
		}elseif(strtoupper($method) === 'DELETE'){
			$curl_opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
			if(is_array($body)){
				$curl_opts[CURLOPT_POSTFIELDS] = json_encode($body);
				$headers[] = 'Content-Type: application/json';
				$curl_opts[CURLOPT_HTTPHEADER] = $headers;
			}
		}

		curl_setopt_array($ch, $curl_opts);

		$response = curl_exec($ch);
		$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		$curl_error = curl_error($ch);
		curl_close($ch);

		if($response === false){
			return array('output' => 'REST request failed: ' . ($curl_error ?: 'unknown error'), 'is_error' => true);
		}

		$decoded = json_decode($response, true);
		if(json_last_error() !== JSON_ERROR_NONE){
			return array('output' => $response, 'is_error' => $http_code >= 400);
		}

		if($http_code >= 400 && is_array($decoded)){
			$message = isset($decoded['message']) ? $decoded['message'] : json_encode($decoded);
			return array('output' => 'REST error (' . $http_code . '): ' . $message, 'is_error' => true);
		}

		return array('output' => json_encode($decoded, JSON_PRETTY_PRINT), 'is_error' => false);
	}

	public function get_posts($args){
		if(!empty($args['id'])){
			return $this->request('GET', 'posts/' . intval($args['id']));
		}
		return $this->request('GET', 'posts', $this->filter_args($args, array('per_page', 'page', 'status', 'search', 'author', 'categories', 'tags')));
	}

	public function manage_post($action, $data){
		$action = strtolower($action);
		if($action === 'create'){
			return $this->request('POST', 'posts', $this->filter_args($data, array('title', 'content', 'status', 'categories', 'tags', 'excerpt')));
		}
		if($action === 'update'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Post ID is required for update', 'is_error' => true);
			return $this->request('PUT', 'posts/' . $id, $this->filter_args($data, array('title', 'content', 'status', 'categories', 'tags', 'excerpt')));
		}
		if($action === 'delete'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Post ID is required for delete', 'is_error' => true);
			return $this->request('DELETE', 'posts/' . $id . '?force=' . (isset($data['force']) ? intval($data['force']) : 1));
		}
		return array('output' => 'Unknown post action: ' . $action, 'is_error' => true);
	}

	public function get_pages($args){
		if(!empty($args['id'])){
			return $this->request('GET', 'pages/' . intval($args['id']));
		}
		return $this->request('GET', 'pages', $this->filter_args($args, array('per_page', 'page', 'status', 'search', 'author', 'categories', 'tags')));
	}

	public function manage_page($action, $data){
		$action = strtolower($action);
		if($action === 'create'){
			return $this->request('POST', 'pages', $this->filter_args($data, array('title', 'content', 'status', 'categories', 'tags', 'excerpt')));
		}
		if($action === 'update'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Page ID is required for update', 'is_error' => true);
			return $this->request('PUT', 'pages/' . $id, $this->filter_args($data, array('title', 'content', 'status', 'categories', 'tags', 'excerpt')));
		}
		if($action === 'delete'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Page ID is required for delete', 'is_error' => true);
			return $this->request('DELETE', 'pages/' . $id . '?force=' . (isset($data['force']) ? intval($data['force']) : 1));
		}
		return array('output' => 'Unknown page action: ' . $action, 'is_error' => true);
	}

	public function get_terms($taxonomy, $args){
		if(!in_array($taxonomy, array('category', 'post_tag'), true)){
			return array('output' => 'Unsupported taxonomy: ' . $taxonomy, 'is_error' => true);
		}
		return $this->request('GET', $taxonomy === 'post_tag' ? 'tags' : 'categories', $this->filter_args($args, array('per_page', 'page', 'search')));
	}

	public function manage_term($action, $data){
		$action = strtolower($action);
		$taxonomy = isset($data['taxonomy']) ? $data['taxonomy'] : 'category';
		$endpoint = $taxonomy === 'post_tag' ? 'tags' : 'categories';

		if($action === 'create'){
			return $this->request('POST', $endpoint, $this->filter_args($data, array('name', 'slug', 'description')));
		}
		if($action === 'update'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Term ID is required for update', 'is_error' => true);
			return $this->request('PUT', $endpoint . '/' . $id, $this->filter_args($data, array('name', 'slug', 'description')));
		}
		if($action === 'delete'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Term ID is required for delete', 'is_error' => true);
			return $this->request('DELETE', $endpoint . '/' . $id . '?force=1');
		}
		return array('output' => 'Unknown term action: ' . $action, 'is_error' => true);
	}

	public function get_comments($args){
		if(!empty($args['id'])){
			return $this->request('GET', 'comments/' . intval($args['id']));
		}
		return $this->request('GET', 'comments', $this->filter_args($args, array('per_page', 'page', 'status', 'post')));
	}

	public function manage_comment($action, $data){
		$action = strtolower($action);
		$id = isset($data['id']) ? intval($data['id']) : 0;
		if(empty($id)) return array('output' => 'Comment ID is required', 'is_error' => true);

		if($action === 'approve'){
			return $this->request('PUT', 'comments/' . $id, array('status' => 'approved'));
		}
		if($action === 'spam'){
			return $this->request('PUT', 'comments/' . $id, array('status' => 'spam'));
		}
		if($action === 'trash'){
			return $this->request('DELETE', 'comments/' . $id);
		}
		if($action === 'delete'){
			return $this->request('DELETE', 'comments/' . $id . '?force=1');
		}
		return array('output' => 'Unknown comment action: ' . $action, 'is_error' => true);
	}

	public function get_media($args){
		if(!empty($args['id'])){
			return $this->request('GET', 'media/' . intval($args['id']));
		}
		return $this->request('GET', 'media', $this->filter_args($args, array('per_page', 'page', 'search')));
	}

	public function manage_media($action, $data){
		$action = strtolower($action);
		if($action === 'delete'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'Media ID is required', 'is_error' => true);
			return $this->request('DELETE', 'media/' . $id . '?force=1');
		}
		return array('output' => 'Media action not implemented: ' . $action, 'is_error' => true);
	}

	public function get_plugins($args){
		$args = $this->filter_args($args, array('status'));
		return $this->request('GET', 'plugins', $args);
	}

	public function manage_plugin($action, $data){
		$action = strtolower($action);
		$plugin = isset($data['plugin']) ? $data['plugin'] : '';
		$slug = isset($data['slug']) ? $data['slug'] : '';

		if($action === 'activate'){
			if(empty($plugin)) return array('output' => 'Plugin identifier is required', 'is_error' => true);
			return $this->request('PUT', 'plugins/' . rawurlencode($plugin), array('status' => 'active'));
		}
		if($action === 'deactivate'){
			if(empty($plugin)) return array('output' => 'Plugin identifier is required', 'is_error' => true);
			return $this->request('PUT', 'plugins/' . rawurlencode($plugin), array('status' => 'inactive'));
		}
		if($action === 'install'){
			if(empty($slug)) return array('output' => 'Plugin slug is required', 'is_error' => true);
			$body = array('slug' => $slug);
			if(!empty($data['url'])) $body['url'] = $data['url'];
			return $this->request('POST', 'plugins', $body);
		}
		if($action === 'update'){
			if(empty($plugin)) return array('output' => 'Plugin identifier is required', 'is_error' => true);
			return $this->request('POST', 'plugins/' . rawurlencode($plugin), array('action' => 'update'));
		}
		if($action === 'delete'){
			if(empty($plugin)) return array('output' => 'Plugin identifier is required', 'is_error' => true);
			return $this->request('DELETE', 'plugins/' . rawurlencode($plugin));
		}
		return array('output' => 'Unknown plugin action: ' . $action, 'is_error' => true);
	}

	public function get_themes($args){
		return $this->request('GET', 'themes', $this->filter_args($args, array('status', 'search')));
	}

	public function manage_theme($action, $data){
		$action = strtolower($action);
		$stylesheet = isset($data['stylesheet']) ? $data['stylesheet'] : '';
		$slug = isset($data['slug']) ? $data['slug'] : '';

		if($action === 'activate'){
			if(empty($stylesheet)) return array('output' => 'Theme stylesheet is required', 'is_error' => true);
			return $this->request('POST', 'themes/' . rawurlencode($stylesheet), array('status' => 'active'));
		}
		if($action === 'install'){
			if(empty($slug)) return array('output' => 'Theme slug is required', 'is_error' => true);
			return $this->request('POST', 'themes', array('slug' => $slug));
		}
		if($action === 'delete'){
			if(empty($stylesheet)) return array('output' => 'Theme stylesheet is required', 'is_error' => true);
			return $this->request('DELETE', 'themes/' . rawurlencode($stylesheet));
		}
		return array('output' => 'Unknown theme action: ' . $action, 'is_error' => true);
	}

	public function get_users($args){
		if(!empty($args['id'])){
			return $this->request('GET', 'users/' . intval($args['id']));
		}
		return $this->request('GET', 'users', $this->filter_args($args, array('per_page', 'page', 'search', 'role')));
	}

	public function manage_user($action, $data){
		$action = strtolower($action);
		if($action === 'create'){
			return $this->request('POST', 'users', $this->filter_args($data, array('username', 'email', 'role', 'password', 'display_name')));
		}
		if($action === 'update'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'User ID is required for update', 'is_error' => true);
			return $this->request('PUT', 'users/' . $id, $this->filter_args($data, array('email', 'role', 'password', 'display_name')));
		}
		if($action === 'delete'){
			$id = isset($data['id']) ? intval($data['id']) : 0;
			if(empty($id)) return array('output' => 'User ID is required for delete', 'is_error' => true);
			$reassign = isset($data['reassign']) ? intval($data['reassign']) : 0;
			return $this->request('DELETE', 'users/' . $id . '?force=1' . ($reassign ? '&reassign=' . $reassign : ''));
		}
		return array('output' => 'Unknown user action: ' . $action, 'is_error' => true);
	}

	public function get_settings(){
		return $this->request('GET', 'settings');
	}

	public function update_settings($data){
		$allowed = array('title', 'description', 'timezone_string', 'date_format', 'time_format', 'posts_per_page', 'default_category', 'show_on_front', 'page_on_front', 'page_for_posts');
		$body = array();
		foreach($allowed as $key){
			if(isset($data[$key])){
				$body[$key] = $data[$key];
			}
		}
		if(empty($body)){
			return array('output' => 'No whitelisted setting provided', 'is_error' => true);
		}
		return $this->request('PUT', 'settings', $body);
	}

	public function get_core_info(){
		$settings = $this->get_settings();
		if($settings['is_error']){
			return $settings;
		}

		$settings_data = json_decode($settings['output'], true);
		if(!is_array($settings_data)){
			$settings_data = array();
		}

		$version_file = ABSPATH . 'wp-includes/version.php';
		$wp_version = '';
		if(file_exists($version_file)){
			$content = file_get_contents($version_file);
			if(preg_match('/\$wp_version\s*=\s*[\'"]([^\'"]+)[\'"]/', $content, $m)){
				$wp_version = $m[1];
			}
		}

		$info = array(
			'wp_version' => $wp_version,
			'siteurl' => isset($settings_data['url']) ? $settings_data['url'] : $this->siteurl,
			'home' => isset($settings_data['home']) ? $settings_data['home'] : '',
			'title' => isset($settings_data['title']) ? $settings_data['title'] : '',
			'description' => isset($settings_data['description']) ? $settings_data['description'] : '',
			'permalink_structure' => isset($settings_data['permalink_structure']) ? $settings_data['permalink_structure'] : '',
		);

		return array('output' => json_encode($info, JSON_PRETTY_PRINT), 'is_error' => false);
	}

	public function core_action($action, $data = array()){
		$action = strtolower($action);
		$valid = array('flush_rewrites', 'clear_cache', 'check_update');
		if(!in_array($action, $valid, true)){
			return array('output' => 'Unknown core action: ' . $action, 'is_error' => true);
		}
		return $this->request('POST', 'core/action', array('action' => $action));
	}

	private function filter_args($args, $allowed){
		if(!is_array($args)) return array();
		$result = array();
		foreach($allowed as $key){
			if(isset($args[$key]) && $args[$key] !== ''){
				$result[$key] = $args[$key];
			}
		}
		return $result;
	}
}
