<?php

class ItemSearch {

	private $config;
	protected $base_object;
	protected $db;

	private $searchData = array();
	private $pageOffset = 0;


	public function __construct($base_object) {
		$this->config = $base_object->config;
		$this->db = $base_object->db;
		$this->base_object = $base_object;
	}

	public function searchItems($searchString) {
		$timer_start = microtime(true);
		//echo "searchItems called<br>";

		//$searchString_trimmed = trim($searchString);
		//$searchString_filtered = preg_replace("@[^\p{L}\p{N}]@sui", '', $searchString_trimmed);

		$this->pageOffset = isset($_GET["page"]) ? ($_GET["page"] - 1) : 0;
		$results = Array();
		
		// CLEAN SEARCH STRATEGY: Fast + Smart only!
		$byNumber = $this->_getItemByNumber($searchString);  // FAST: Direct number/EAN
		
		$byKrempl = $this->_getItembyKremplNumber($searchString);  // SMART: Device models, part numbers
		
		$results = array_merge($results, $byNumber);
		$results = array_merge($results, $byKrempl);
		
		// REMOVE DUPLICATES (array keys automatically handle this)
		$results = array_unique($results);

		$running_time = microtime(true) - $timer_start;

		// Paginate result (make solution cleaner in the future)
		//$results = array_splice($results, 0, 20);

		//echo "results number: ".count($results)."<br>";
		$result = array(
			'searchstring' => $searchString,
			'results' => count($results),
			'queryTime' => $running_time,
			'data' => $results
		);

		return $result;
	}

	private function _searchItemWithinItemsAndAssociations($searchManufacturer, $searchString, $idsOnly = false, $searchManufacturer_filtered = false, $searchString_filtered = false, $searchRefinement_filtered = false) {
 		$queries = $this->_queryLike($searchManufacturer_filtered, $searchString);

		$results = array();

		$idArray = array();
		foreach ($queries as $query) {
			$rs = $this->db->query($query);
			if (!$rs) break;

			while ($I = $rs->fetch_object()) {
				if ($I->anumber) {
					$results[$I->anumber] = $I->anumber;
					$idArray[] = $I->anumber;
				}
			}
		}
		//$idArray = $this->_getIdsByNumbers($results, true, $searchRefinement_filtered);

		return $idArray;
	}

	private function _getIdsByNumbers($numbers, $withAlternatives = true, $refinement = false) {
		if (is_array($numbers) && count($numbers) > 0) {
			$numberList = implode("','", $numbers);

			$queryAddAlternatives = '';
			if ($withAlternatives) {
				$queryAddAlternatives = " OR attribute_17 IN ('".$numberList."')";
			}

			$queryAddRefinement = '';
			if ($refinement) {
				$refinement = $this->db->real_escape_string($refinement);
				$queryAddRefinement = "
					AND (
						name LIKE '%".$refinement."%'
					OR
						detail_description LIKE '%".$refinement."%'
					OR
						detail_description LIKE '%".htmlentities($refinement, null, 'UTF-8')."%'
					OR
						attribute_1 LIKE '%".$refinement."%'
					OR
						attribute_9 LIKE '%".$refinement."%'
					OR
						attribute_20 LIKE '%".$refinement."%'
					OR
						attribute_6 LIKE '%".$refinement."%'
					)
				";
				$queryAddRefinement = "
					AND (
						name LIKE '%".$refinement."%'
					OR
						attribute_1 LIKE '%".$refinement."%'
					OR
						attribute_9 LIKE '%".$refinement."%'
					OR
						attribute_20 LIKE '%".$refinement."%'
					OR
						attribute_6 LIKE '%".$refinement."%'
					)
				";
			}

			/*$query = "
				SELECT
					id
				FROM
					items
				WHERE (
					number IN ('".$numberList."') OR
					number IN ('".$numberList."')
					".$queryAddAlternatives."
				)
				".$queryAddRefinement."
			";*/
			$query = "
				SELECT
					id
				FROM
					items
				WHERE 
					number IN ('".$numberList."')
				LIMIT 150";
			$idArray = array();
			$rs = $this->db->query($query);
			if (!$rs) return $idArray;
			//echo '<pre>';echo $query;exit();
			while ($I = $rs->fetch_object()) {
				$idArray[$I->id] = $I->id;
			}

			return $idArray;
		}

		return array();
	}

	private function _queryLike($searchManufacturer_filtered, $searchString_filtered) {
		//$searchManufacturer_filtered = $this->db->real_escape_string($searchManufacturer_filtered);
		$searchString_filtered = $this->db->real_escape_string($searchString_filtered);

		$queries = array();

		if (ctype_alpha($searchString_filtered)) {
			$queries[] = "
				SELECT 
					id AS anumber
				FROM 
					items 
				WHERE 
					active = 1 
				AND 
					parent_id = 0 
				AND (
					REPLACE(REPLACE(REPLACE(vendor_item_number, ' ', ''), '/', ''), '-', '') LIKE '%".$searchString_filtered."%'
				OR
					-- mögliche Aufschrift
					attribute_4 LIKE '%".$searchString_filtered."%' 
				OR
					-- Aufdrucke
					attribute_9 LIKE '%".$searchString_filtered."%' 
				OR
					-- Synonyme
					attribute_6 LIKE '%".$searchString_filtered."%'  
				)
				GROUP BY number LIMIT 150";
		} else {
			$forwardSlashPos = strpos($searchString_filtered, "/");
			if ($forwardSlashPos != false) {
				$searchString_filtered = substr($searchString_filtered, 0, $forwardSlashPos);
			}

			if (!ctype_digit($searchString_filtered) || (ctype_digit($searchString_filtered) && strlen($searchString_filtered) >= 6)) {
				// STEP-BY-STEP APPROACH (NO BIG JOINS!)
				$device_query = "SELECT DISTINCT kg.id FROM krempl_geraete_22 kg
				                WHERE REPLACE(REPLACE(REPLACE(kg.nr, ' ', ''), '/', ''), '-', '') LIKE '%".$searchString_filtered."%'
				                OR REPLACE(REPLACE(REPLACE(kg.bezeichnungoriginal, ' ', ''), '/', ''), '-', '') LIKE '%".$searchString_filtered."%'
				                LIMIT 50";
				
				$device_rs = $this->db->query($device_query);
				if ($device_rs && $device_rs->num_rows > 0) {
					$device_ids = $this->collapseResultRows($device_rs->fetch_all(MYSQLI_NUM));
					
					if (!empty($device_ids)) {
						$ersatzteil_query = "SELECT DISTINCT ka.ersatzteil FROM krempl_artikelgeraet_22 ka 
						                    WHERE " . $this->queryOrConcat("ka.geraet", $device_ids) . " LIMIT 300";
						
						$ersatzteil_rs = $this->db->query($ersatzteil_query);
						if ($ersatzteil_rs && $ersatzteil_rs->num_rows > 0) {
							$ersatzteil_ids = $this->collapseResultRows($ersatzteil_rs->fetch_all(MYSQLI_NUM));
							
							if (!empty($ersatzteil_ids)) {
								$queries[] = "SELECT DISTINCT i.id AS anumber FROM items i 
								             WHERE " . $this->queryOrConcat("i.krempl_id", $ersatzteil_ids) . " LIMIT 150";
							}
						}
					}
				}
			}

			$queries[] = "
				SELECT 
					DISTINCT items.id AS anumber
				FROM 
					krempl_passendwie pw
				LEFT JOIN 
					items on items.number=pw.navisionid OR items.attribute_7=pw.navisionid
				WHERE
					REPLACE(REPLACE(REPLACE(bestellcode, ' ', ''), '/', ''), '-', '') LIKE '%".$searchString_filtered."%'
				LIMIT 150";

			$queries[] = "SELECT id AS anumber FROM items WHERE active = 1 AND 
				REPLACE(REPLACE(REPLACE(attribute_20, ' ', ''), '/', ''), '-', '') LIKE '%".$searchString_filtered."%' 
				GROUP BY number LIMIT 150";
		}
		return $queries;
	}

	private function _getItemByNumber($searchString_ready) {
		if (!is_numeric($searchString_ready)) return Array();

		$query = "
			SELECT id FROM items WHERE
				number = '".$this->db->real_escape_string($searchString_ready)."' OR
				attribute_7 = '".$this->db->real_escape_string($searchString_ready)."' OR
				ean_code = '".$this->db->real_escape_string($searchString_ready)."' 
			LIMIT 150";

		$rs = $this->db->query($query);

		$idArray = array();
		if ($rs->num_rows > 0) {
			while ($I = $rs->fetch_object()) {
				$idArray[$I->id] = $I->id;
			}
			return $idArray;
		} else {
			return Array();
		}
	}

	private function _getItemByText($searchString_ready) {
		$query = "
			SELECT id FROM items WHERE
				name LIKE '%".$this->db->real_escape_string($searchString_ready)."%' OR
				attribute_20 like '%".$this->db->real_escape_string($searchString_ready)."%' OR
				short_description like '%".$this->db->real_escape_string($searchString_ready)."%' OR
				detail_description like '%".$this->db->real_escape_string($searchString_ready)."%'
			LIMIT 150";
		$rs = $this->db->query($query);

		$idArray = array();
		if ($rs->num_rows > 0) {
			while ($I = $rs->fetch_object()) {
				$idArray[$I->id] = $I->id;
			}
			return $idArray;
		} else {
			return Array();
		}
	}

	private function _getItembyKremplNumberOld($searchString) {

		$query = 'SELECT kg.id FROM `krempl_geraete_22` kg where nr LIKE "%'.$searchString.'%" or modellBezeichnung LIKE "%'.$searchString.'%";';
		$rs = $this->db->query($query);

		$idArray = array();
		if ($rs->num_rows > 0) {
			$ids = $rs->fetch_all(MYSQLI_NUM)[0];
			foreach ($ids as $id) {
				$sql = "
					SELECT i.id FROM `krempl_item` ki
					left join krempl_artikelgeraet_22 ka on ki.id = ka.ersatzteil 
					left join krempl_geraete_22 kg ON kg.id = ka.geraet
					left join items i ON ki.navisionid = i.attribute_7 
					WHERE ka.geraet = ".$id." ORDER BY `ki`.`navisionid` ASC;
				";
				/* //TEST ZUM OPTIMIEREN
				$sql = "
					SELECT i.* FROM items i
					INNER JOIN krempl_item ki ON i.attribute_7 = ki.navisionid
					INNER JOIN krempl_artikelgeraet_22 ka ON ki.id = ka.ersatzteil 
					WHERE ka.geraet IN (
						SELECT kg.id FROM `krempl_geraete_22` kg where nr LIKE "%AR 1268 TXNL%" or modellBezeichnung LIKE "%AR 1268 TXNL%"
					);
				";
				*/
				$rs = $this->db->query($sql);

				if ($rs->num_rows > 0) {
					while ($I = $rs->fetch_object()) {
						if (isset($I->id))
							$idArray[$I->id] = $I->id;
					}
				}
			}
		}
		return $idArray;
	}

	private function _getItembyKremplNumber($searchString) {
		//echo "<script>console.log('_getItembyKremplNumber called with: $searchString');</script>";
		
		if (empty(trim($searchString))) {
			echo "<script>console.log('EMPTY searchString, returning');</script>";
			return Array();
		}

		/*$query = '
			CREATE TEMPORARY TABLE temp_kg_ids (id INT);

			INSERT INTO temp_kg_ids (id)
			SELECT kg.id
			FROM krempl_geraete_22 kg 
			WHERE kg.nr LIKE "%'.$searchString.'%" OR kg.modellBezeichnung LIKE "%'.$searchString.'%";
			
			CREATE TEMPORARY TABLE temp_ersatzteile (ersatzteil INT);
			
			INSERT INTO temp_ersatzteile (ersatzteil)
			SELECT ka.ersatzteil
			FROM krempl_artikelgeraet_22 ka
			JOIN temp_kg_ids tempkg ON ka.geraet = tempkg.id;
			
			SELECT i.id
			FROM items i
			JOIN krempl_item ki ON i.attribute_7 = ki.navisionid
			JOIN temp_ersatzteile tempersatz ON ki.id = tempersatz.ersatzteil
			ORDER BY ki.navisionid ASC;
			
			DROP TEMPORARY TABLE IF EXISTS temp_kg_ids;
			DROP TEMPORARY TABLE IF EXISTS temp_ersatzteile;
		';
		$rs = $this->db->query($query);
		return $rs->fetch_all(MYSQLI_NUM)[0];*/

		// STEP 1: Find devices by model/nr (EXACT match like Python!)
		$searchString_escaped = $this->db->real_escape_string($searchString);
		$query = "SELECT kg.id FROM krempl_geraete_22 kg 
		          WHERE kg.nr LIKE '%{$searchString_escaped}%' 
		          OR kg.modellBezeichnung = '{$searchString_escaped}'
		          LIMIT 50";
		
		$rs = $this->db->query($query);
		if (!$rs || $rs->num_rows <= 0) return Array();
		
		$device_ids = $this->collapseResultRows($rs->fetch_all(MYSQLI_NUM));
		if (empty($device_ids)) return Array();
		
		// STEP 2: Find ersatzteile for devices (SMALL QUERY!)
		$query = "SELECT DISTINCT ka.ersatzteil 
		          FROM krempl_artikelgeraet_22 ka 
		          WHERE " . $this->queryOrConcat("ka.geraet", $device_ids) . "
		          LIMIT 300";
		
		$rs = $this->db->query($query);
		if (!$rs || $rs->num_rows <= 0) return Array();
		
		$ersatzteil_ids = $this->collapseResultRows($rs->fetch_all(MYSQLI_NUM));
		if (empty($ersatzteil_ids)) return Array();

		// STEP 3: Find items directly by krempl_id (NO krempl_item table!)
		$query = "SELECT i.id 
		          FROM items i 
		          WHERE " . $this->queryOrConcat("i.krempl_id", $ersatzteil_ids) . "
		          LIMIT 150";
		
		$rs = $this->db->query($query);
		if (!$rs || $rs->num_rows <= 0) return Array();

		$idArray = Array();
		foreach ($this->collapseResultRows($rs->fetch_all(MYSQLI_NUM)) as $i) {
			$idArray[(int) $i] = (int) $i;
		}
		return $idArray;
	}

	private function queryOrConcat($varName, $arr) {
		$ret = "$varName = ";
		if (count($arr) <= 1) return $ret.$arr[0];

		for ($i = 0; $i < count($arr) - 1; $i++) {
			$ret .= $arr[$i]." OR $varName = ";
		}
		$ret .= $arr[count($arr) - 1];
		return $ret;
	}

	private function collapseResultRows($arr) { // takes a multilevel array returned by mysqli->fetch_all(MYSQLI_NUM) and collapses it to a monodimensional array
		$ret = Array();
		foreach ($arr as $a) {
			$ret[] = $a[0];
		}
		return $ret;
	}

}