<?php

require_once(__DIR__ . "/File.php");
require_once(__DIR__ . "/HTTPRequest.php");

class Gemini {

	public $file_uri = "";

	public $root = "https://generativelanguage.googleapis.com";

	public $verbose = false;

	private $_upload_callback = false;
	private $_process_callback = false;

	public static function get_key() {
		$i = 0;
		$keys = [];

		while ($k = Config::get("GEMINI_KEY_" . $i)) {
			$keys[] = $k;
			$i++;
		}

		$keyid = rand(0, count($keys) - 1);

		$key = $keys[$keyid];
		return $key;
	}

	public function upload_file(File $file, $key = false) {

		set_time_limit(300);

		if ($this->verbose) {
			print("Uploading file...\n");
        	flush();
		}
		$cb = false;

		if ($this->_upload_callback) {
			$cb = $this->_upload_callback;
		}

	 	if ($cb) $cb(0);
		

		if ($key == false) {
			$key = Gemini::get_key();
		}

		$json = "{'file': {'display_name': '" . $file->basename() . "'}}";

		if ($this->verbose) {
			print("Upload data: " . $json . "\n");
			flush();
		}


		$h = new HTTPRequest();

		$r = $h->post($this->root . "/upload/v1beta/files", $json, [
			"x-goog-api-key: " . $key,
			"Content-Type: application/json",
			"X-Goog-Upload-Protocol: resumable",
			"X-Goog-Upload-Command: start",
			"X-Goog-Upload-Header-Content-Length: " . $file->size(),
			"X-Goog-Upload-Header-Content-Type: " . $file->mime()
		]);

		if ($this->verbose) {
			print("Request data:\n");
			print_r($h);
			flush();
		}

		if ($r != 200) {
			throw new Exception("Error uploading file to Gemini", $r);
		}

		$url = $h->headers['x-goog-upload-url'];
		$chunksize = $h->headers['x-goog-upload-chunk-granularity'];

		$size = $file->size();
		$s = $size;

		$pos = 0;
	
		while ($s > 0) {

			$chunk = min($s, $chunksize);

			$pct = round($pos / $size * 100);
			if ($cb) $cb($pct);

			if ($this->verbose) {
				printf("***** %d%%\n", round($pct));
				flush();
			}

			$data = $file->get_chunk($pos, $chunk);
			$s -= $chunk;

			$fin = $s == 0 ? ", finalize" : "";

			$r = $h->post($url, $data, [
				"Content-Length: " . $chunk,
				"X-Goog-Upload-Offset: " . $pos,
				"X-Goog-Upload-Command: upload$fin" 
			]);

			if ($r != 200) {
				throw new Exception("Error uploading chunk $pos to Gemini", $r);
			}

			if ($this->verbose) {
				print_r($r);
				flush();
			}

			$pos += $chunk;
		}

		$d = json_decode($h->body);

		if ($this->verbose) {
			print("Final returned body:\n");
			print_r($d);
		}

	 	if ($cb) $cb(100);
		return $d->file->uri;
	}

	
	public function geminiOverview(File $file) {

		$cb = false;
		if ($this->_process_callback) $cb = $this->_process_callback;

		if ($cb) $cb("Uploading file");

		if ($this->verbose) {
			print("<pre>");
		}

		$key = Gemini::get_key();

		$uri = $this->upload_file($file, $key);

		
		$ob = [
		  "contents" => [
			[
			  "parts" => [
				[
				  "text" => "Summarize this document. In addition provide me the title of the document as the first line, surrounded by { and }. If it is all in capitals, re-capitalize it to make it easier to read. On the second line give the document order number surrounded by [ and ].",
				],
				[
				  "file_data" => [
					"mime_type" => $file->mime(),
					"file_uri" => $uri
				  ]
				]
			  ]
			]
		  ]
		];

		$json = json_encode($ob, JSON_PRETTY_PRINT);

		if ($this->verbose) {
			print("AI reuqest: " . $json . "\n");
			flush();
		}
		set_time_limit(300);


		if ($cb) $cb("Sending request");

		$h = new HTTPRequest();
		$r = $h->post($this->root . "/v1beta/models/gemini-2.5-flash-lite:generateContent", $json, [
			"x-goog-api-key: " . $key,
			"Content-Type: application/json"
		]);

		if ($cb) $cb("Processing response");

		if ($this->verbose) {
			print("AI Response:\n");
			print_r($h);
			flush();
		}

		$resp = json_decode($h->body);

		if ($r != 200) {
			if (@$resp->error) {
				throw new Exception($resp->error->message, $resp->error->code);
			} else {
				throw new Exception("HTTP Error $r requesting AI assistance", $r);
			}
		}

		if (property_exists($resp, "candidates")) {
			$text = $resp->candidates[0]->content->parts[0]->text;
			$lines = explode("\n", $text);

			$lastLine = "";
			$out = [];
			foreach ($lines as $line) {
				if (str_starts_with($line, "* ") and !str_starts_with($lastLine, "* ")) {
					$lastLine = $line;
					$line = "\n" . $line;
				} else if (str_starts_with($line, "1. ") and (trim($lastLine) != "")) {
					$lastLine = $line;
					$line = "\n" . $line;
				} else {
					$lastLine = $line;
				}

				$out[] = $line;
			}

		
			return implode("\n", $out);
		}

		throw new Exception("Content missing processing AI data", 0);
	}

	public function upload_callback(callable $cb) {
		$this->_upload_callback = $cb;
	}

	public function process_callback(callable $cb) {
		$this->_process_callback = $cb;
	}
}
