<?php

class MySQLAdapter {
	public $raw;

	function __construct() {
		$db_params = json_decode(file_get_contents('secrets/db.json'), true);

		try {
			if(false !== getenv('MYSQL_HOST')) {
				$this->raw = mysqli_connect(getenv('MYSQL_HOST'), 
					getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'), 
					getenv('MYSQL_DATABASE'),
					getenv('MYSQL_PORT'));
			}
			else {
				$this->raw = mysqli_connect($db_params['MYSQL_HOST'], 
					$db_params['MYSQL_USER'], $db_params['MYSQL_PASSWORD'], 
					$db_params['MYSQL_DATABASE'],
					$db_params['MYSQL_PORT']);
			}
		} catch (\Throwable $th) {
			echo 'Connection failed<br>';
			echo 'Error number: ' . mysqli_connect_errno() . '<br>';
			echo 'Error message: ' . mysqli_connect_error() . '<br>';
			die();

			//throw $th;
		}
	}

	function _sanitize_path($post_path) {
		$post_path = chop($post_path, '/');

		if($post_path == "") {
			return "";
		}

		if(!preg_match('/^(?:\/[\w-]+)+(?:\.[\w-]+)*$/', $post_path)) {
			echo "Post path match against " . $post_path . " failed!";
			die();
		}

		return $post_path;
	}

	function _exec($qery, $argtypes, ...$args) {
		$stmt = $this->raw->prepare($qery);
		$stmt->bind_param($argtypes, ...$args);
		$stmt->execute();

		return $stmt->get_result();
	}

	function _normalize_post_data($post_data) {
		if($post_data == null) {
			return [
				"found" => false
        	];
    	}
    	
		$post_data["found"] = true;

		$post_data['post_metadata'] = json_decode($post_data["post_metadata"], true) ?? [];
		$post_data["post_content"] ??= '';

		return $post_data;
	}

	function bump_post($post_path, $post_metadata = [], $create_dirs = true) {
		$post_path = $this->_sanitize_path($post_path);
		$path_depth = substr_count($post_path, "/");

		if($create_dirs) {
			$this->make_post_directory(dirname($post_path));
		}

		$qry = "
		INSERT INTO posts
			(post_path, post_path_depth, post_metadata, post_content)
		VALUES
			( ?, ?, ?, ?) AS new
		ON DUPLICATE KEY UPDATE post_path=new.post_path;";

		$this->_exec($qry, "siss", 
			$post_path,
			$path_depth,
			json_encode($post_metadata),
			'');
	}

	function make_post_directory($directory) {
		$json_metadata = ["type" => 'directory'];
		
		while(strlen($directory) > 1) {
			try {
				$this->bump_post($directory, $json_metadata, false);
			}
			catch(Exception $e) {
			}

			$directory = dirname($directory);
		}
	}

	function update_or_create_post($post_path, $post_metadata, $post_content) {
		$post_path = $this->_sanitize_path($post_path);
		$path_depth = substr_count($post_path, "/");
		
		$this->make_post_directory(dirname($post_path));

		$qry = "
		INSERT INTO posts
			(post_path, post_path_depth, post_metadata, post_content)
		VALUES
			( ?, ?, ?, ?) AS new
		ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content;";

		$this->_exec($qry, "siss", 
			$post_path,
			$path_depth,
			json_encode($post_metadata),
			$post_content);
	}

	function get_settings_for_path($post_path) {
		$post_path = $this->_sanitize_path($post_path);

		$qry = "
		WITH RECURSIVE settings_data (post_path, post_depth, json_settings) AS (
			SELECT post_path, post_path_depth, post_metadata
			FROM posts
			WHERE post_path = ?

			UNION ALL 

			SELECT posts.post_path, posts.post_path_depth, posts.post_metadata
			FROM posts, settings_data
			WHERE posts.post_path = SUBSTRING_INDEX(settings_data.post_path, '/', settings_data.post_depth)
				AND posts.post_path_depth = settings_data.post_depth - 1
		)
		SELECT post_depth, json_settings 
		FROM settings_data
		ORDER BY post_depth ASC;
		";

		$out_settings = [];

		$settings_list = $this->_exec($qry, "s", $post_path)->fetch_all(MYSQLI_ASSOC);

		foreach($settings_list AS $setting) {			
			$setting = json_decode($setting['json_settings'], true);

			if(!isset($setting) || !isset($setting['settings'])) {
				continue;
			}

			$out_settings = array_merge($out_settings, $setting['settings']);
		}

		return $out_settings;
	}
	
	function get_post_by_path($post_path, 
			$with_subposts = false, $with_settings = true) {
		
		$qry = "SELECT * FROM posts WHERE post_path = ?";
		$post_path = $this->_sanitize_path($post_path);

		$post_data = $this->_exec($qry, "s", $post_path)->fetch_assoc();
		$post_data = $this->_normalize_post_data($post_data);

		$post_data['post_path'] = $post_path;
		
		if(!$post_data['found']) {
			return $post_data;
		}

		if($with_subposts) {
			$post_data['subposts'] = $this->get_subposts_by_path($post_path);
		}
		if($with_settings) {
			$post_data['settings'] = $this->get_settings_for_path($post_path);
		}

		return $post_data;
	}

	function get_subposts_by_path($path) {
	    global $sql;
	
	    $path = $this->_sanitize_path($path);
	
	    $path_depth = substr_count($path, "/");
	
	    $qry = "SELECT post_path, post_metadata, post_update_time
	        FROM posts 
	        WHERE (post_path LIKE CONCAT(?,'/%')) 
	            AND post_path_depth = ?
	            ORDER BY post_create_time DESC
	            LIMIT 10";

	   $post_data = $this->_exec($qry, "si", $path, $path_depth+1)->fetch_all(MYSQLI_ASSOC);

		$fn = function($data) {
			return $this->_normalize_post_data($data);
		};
		
	    $post_data = array_map($fn, $post_data);
	
	    return $post_data; 
	}
}

?>
