<?php

new autocomplete();

class autocomplete{
	
	public function __construct(){
		
		header("Content-Type: application/json");
		
		$this->scrapers = [
			"brave" => "https://search.brave.com/api/suggest?q={searchTerms}",
			"ddg" => "https://duckduckgo.com/ac/?q={searchTerms}&type=list",
			"yandex" => "https://suggest.yandex.com/suggest-ff.cgi?part={searchTerms}&uil=en&v=3&sn=5&lr=21276&yu=4861394161661655015",
			"google" => "https://www.google.com/complete/search?client=mobile-gws-lite&q={searchTerms}",
			"qwant" => "https://api.qwant.com/v3/suggest/?q={searchTerms}&client=opensearch",
			"yep" => "https://api.yep.com/ac/?query={searchTerms}",
			"marginalia" => "https://search.marginalia.nu/suggest/?partial={searchTerms}",
			"yt" => "https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&q={searchTerms}",
			"sc" => "https://api-v2.soundcloud.com/search/queries?q={searchTerms}&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=10&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en"
		];
		
		/*
			Sanitize input
		*/
		if(!isset($_GET["s"])){
			
			$this->do404("Missing search(s) parameter");
		}
		
		if(is_string($_GET["s"]) === false){
			
			$this->do404("Invalid search(s) parameter");
		}
		
		if(strlen($_GET["s"]) > 500){
			
			$this->do404("Search(s) exceeds the 500 char length");
		}
		
		if(
			isset($_GET["scraper"]) &&
			is_string($_GET["scraper"]) === false
		){
			
			$_GET["scraper"] = "brave"; // default option
		}
		
		/*
			Get $scraper
		*/
		if(!isset($_GET["scraper"])){
			
			if(isset($_COOKIE["scraper_ac"])){
				
				$scraper = $_COOKIE["scraper_ac"];
			}else{
				
				$scraper = "brave"; // default option
			}
		}else{
			
			$scraper = $_GET["scraper"];
		}
		
		if($scraper == "disabled"){
			
			// this shouldnt happen, but let's handle it anyways
			$this->doempty();
		}
		
		// make sure it exists
		if(!isset($this->scrapers[$scraper])){
			
			$scraper = "brave"; // default option
		}
		
		// return results
		
		switch($scraper){
			
			case "google":
			case "yt":
				// handle google cause they want to be a special snowflake :(
				$js = $this->get($this->scrapers[$scraper], $_GET["s"]);
				
				preg_match(
					'/\((\[.*\])\)/',
					$js,
					$js
				);
				
				if(!isset($js[1])){
					
					$this->doempty();
				}
				
				$js = json_decode($js[1]);
				$json = [];
				
				foreach($js[1] as $item){
					
					$json[] = strip_tags($item[0]);
				}
				
				echo json_encode(
					[
						$_GET["s"],
						$json
					]
				);
				break;
			
			case "sc":
				// soundcloud
				$js = $this->get($this->scrapers[$scraper], $_GET["s"]);
				
				$js = json_decode($js, true);
				
				if(!isset($js["collection"])){
					
					$this->doempty();
				}
				
				$json = [];
				foreach($js["collection"] as $item){
					
					$json[] = $item["query"];
				}
				
				echo json_encode(
					[
						$_GET["s"],
						$json
					]
				);
				break;
			
			case "marginalia":
				$json = $this->get($this->scrapers[$scraper], $_GET["s"]);
				
				$json = json_decode($json, true);
				if($json === null){
					
					
					$this->doempty();
				}
				
				echo json_encode(
					[
						$_GET["s"],
						$json
					]
				);
				break;
			
			default:
				// if it respects the openSearch protocol
				$json = json_decode($this->get($this->scrapers[$scraper], $_GET["s"]), true);
				
				echo json_encode(
					[
						$_GET["s"],
						$json[1] // ensure it contains valid key 0
					]
				);
				break;
		}
	}
	
	private function get($url, $query){
		
		$curlproc = curl_init();
		
		$url = str_replace("{searchTerms}", urlencode($query), $url);
		
		curl_setopt($curlproc, CURLOPT_URL, $url);
		
		curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
		curl_setopt($curlproc, CURLOPT_HTTPHEADER,
			["User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0",
			"Accept: application/json, text/javascript, */*; q=0.01",
			"Accept-Language: en-US,en;q=0.5",
			"Accept-Encoding: gzip",
			"DNT: 1",
			"Connection: keep-alive",
			"Sec-Fetch-Dest: empty",
			"Sec-Fetch-Mode: cors",
			"Sec-Fetch-Site: same-site"]
		);
		
		curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
		curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
		curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
		curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
		
		$data = curl_exec($curlproc);
		
		if(curl_errno($curlproc)){
			
			throw new Exception(curl_error($curlproc));
		}
		
		curl_close($curlproc);
		return $data;
	}
	
	private function do404($error){
		
		echo json_encode(["error" => $error]);
		die();
	}
	
	private function doempty(){
		
		echo json_encode(
			[
				$_GET["s"],
				[]
			]
		);
		die();
	}
}