<?php

use Spatie\YamlFrontMatter\YamlFrontMatter;

class MySQLAdapter {
	public $raw;
	public $data_directory;

	function __construct() {
		$this->raw = mysqli_connect(getenv('MYSQL_HOST'), 
			getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'), getenv('MYSQL_DATABASE'));

		$this->data_directory = 'raw';

		if (!$this->raw)
		{
			echo 'Connection failed<br>';
			echo 'Error number: ' . mysqli_connect_errno() . '<br>';
			echo 'Error message: ' . mysqli_connect_error() . '<br>';
			die();
		}
	}

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

		return $stmt->get_result();
	}
	
	function _prepare_post_data($post_data) {
		if($post_data == null) {
			return [
				"found" => false
        	];
    	}
    	
		$post_data["found"] = true;
		$post_data["post_basename"] = basename($post_data["post_path"]);

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

		$post_meta["title"] ??= basename($post_data["post_path"]);
		
		if(!isset($post_meta['type'])) {
			$type = null;

			$ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION);

			if($ext == '') {
				$type = 'directory';
			} elseif($ext == 'md') {
				$type = 'text/markdown';
			}

			$post_meta['type'] = $type;
		}
		
		$post_data["post_content"] ??= '';
		$post_data["post_file_dir"] = '/' . $this->data_directory . $post_data["post_path"];

		$post_data['post_metadata'] = $post_meta;

    	return $post_data;
	}

	function _fill_post_descriptors($post_data) {

		switch(($post_data['post_metadata']['type'] ?? '')) {
		case 'directory':
			$readme = $this->get_post_by_path($post_data['post_path'] . '/README.md', false);
			$post_data['readme'] = $readme;
			
			if($readme['found']) {
				$post_data['post_metadata']['title'] = $readme['post_metadata']['title'];
			}
		break;

		case 'file':
			$post_data['descriptor'] = $this->get_post_by_path($post_data['post_path'] . '.md', false);
		break;
		}

		return $post_data;
	}

	function ensure_directory($directory) {
		$data_directory = $this->data_directory . $directory;
		
		is_dir($data_directory) || mkdir($data_directory, 0777, true);
		
		$insert_statement = "
			INSERT INTO posts
				(post_path, post_path_depth, post_metadata, post_content)
			VALUES
				(?, ?, ?, '') AS new
			ON DUPLICATE KEY UPDATE post_path=new.post_path 
			";

		$json_metadata = json_encode(["type" => 'directory']);
		
		while(strlen($directory) > 1) {
			try {
				echo "Inserting dir " . $directory . "\n";

				$this->_exec($insert_statement, "sis",
					$directory, substr_count($directory, '/'),
					$json_metadata);

				}
			catch(Exception $e) {
			}
			$directory = dirname($directory);
		}
	}

	function ensure_post_placeholder($post_path, $post_metadata) {
		$post_path = chop($post_path, '/');
		$path_depth = substr_count($post_path, "/");

		$this->ensure_directory(dirname($post_path));

		echo "Bumping post placeholder " . $post_path . "\n";

		$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 create_post_entry($post_path, $post_metadata, $post_content) {
		$post_path = chop($post_path, '/');
		$path_depth = substr_count($post_path, "/");
		
		$this->ensure_directory(dirname($post_path));

		echo "Creating post entry " . $post_path . "\n";

		$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 save_markdown_post($post_path, $post_data) {
		$frontmatter_post = YamlFrontMatter::parse($post_data);
		$post_path = chop($post_path, '/');

		$post_content = $frontmatter_post->body();
		$post_metadata = $frontmatter_post->matter();

		if(basename($post_path) == "README.md") {
			$readme_metadata = $frontmatter_post->matter();
			$readme_metadata['type'] = $post_metadata['readme_type'] ?? 'directory';
			
			$this->create_post_entry(dirname($post_path), $readme_metadata, '');

			$post_metadata['type'] = 'text/markdown';
		}

		$post_metadata['type'] ??= 'text/markdown';

		$this->create_post_entry($post_path, $post_metadata, $post_content);
		file_put_contents($this->data_directory . $post_path,
			$post_data);

	}

	function save_file($post_path, $file_path) {
		$post_metadata = ["type" => 'file'];
		$post_path = chop($post_path, '/');
		
		$this->ensure_post_placeholder($post_path, $post_metadata, '');

		copy($file_path, $this->data_directory . $post_path);
	}

	function handle_upload($post_path, $file_path) {
		$ext = pathinfo($post_path, PATHINFO_EXTENSION);

		switch($ext) {
			case "md":
				$this->save_markdown_post($post_path, file_get_contents($file_path));
			break;
			default:
				$this->save_file($post_path, $file_path);
		}
	}

	function get_post_by_path($post_path, $with_subposts = true) {
		$qry = "SELECT * FROM posts WHERE post_path = ?";

		$post_path = chop($post_path, '/');

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

		$post_data = $this->_fill_post_descriptors($post_data);

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

		return $post_data;
	}

	function get_subposts_by_path($path) {
	    global $sql;
	
	    $path = chop($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->_prepare_post_data($data);
		};
		
	    $post_data = array_map($fn, $post_data);
	
	    return $post_data; 
	}
}

?>
