/*
This file is part of »zeitbild«.

Copyright 2025 'kcf' <fenris@folksprak.org>

»zeitbild« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»zeitbild« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »zeitbild«. If not, see <http://www.gnu.org/licenses/>.
 */



/**
 */
async function main(
	args_raw : Array<string>
) : Promise<void>
{
	// init1
	/*
	lib_plankton.log.set_main_logger(
		[
			{
				"kind": "std",
				"data": {
				}
			}
		]
	);
	 */
	
	// args
	const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({
		"action": lib_plankton.args.class_argument.positional({
			"index": 0,
			"type": lib_plankton.args.enum_type.string,
			"mode": lib_plankton.args.enum_mode.replace,
			"default": "serve",
			"name": "action",
			"info": lib_plankton.string.coin(
				"{{description}}:\n{{options}}\n\t\t",
				{
					"description": "action",
					"options": (
						[
							{
								"name": "serve",
								"description": "serve"
							},
							{
								"name": "api-doc",
								"description": "api-doc"
							},
							{
								"name": "conf-schema",
								"description": "conf-schema"
							},
							{
								"name": "conf-expose",
								"description": "conf-expose"
							},
							{
								"name": "sample",
								"description": "sample"
							},
							{
								"name": "help",
								"description": "help"
							},
						]
						.map(
							entry => lib_plankton.string.coin(
								"\t\t- {{name}}\n\t\t\t{{description}}\n",
								{
									"name": entry.name,
									"description": entry.description,
								}
							)
						)
						.join("")
					),
				}
			),
		}),
		"conf_path": lib_plankton.args.class_argument.volatile({
			"indicators_long": ["conf_path"],
			"indicators_short": ["c"],
			"type": lib_plankton.args.enum_type.string,
			"mode": lib_plankton.args.enum_mode.replace,
			"default": "conf.json",
			// "info": null,
			"name": "conf-path",
		}),
		"data_path": lib_plankton.args.class_argument.volatile({
			"indicators_long": ["data-path"],
			"indicators_short": ["d"],
			"type": lib_plankton.args.enum_type.string,
			"mode": lib_plankton.args.enum_mode.replace,
			"default": "data.json",
			// "info": null,
			"name": "data-path",
		}),
		"help": lib_plankton.args.class_argument.volatile({
			"indicators_long": ["help"],
			"indicators_short": ["h"],
			"type": lib_plankton.args.enum_type.boolean,
			"mode": lib_plankton.args.enum_mode.replace,
			"default": false,
			// "info": null,
			"name": "help",
		}),
	});
	const args : Record<string, any> = arg_handler.read(
		lib_plankton.args.enum_environment.cli,
		args_raw.join(" ")
	);
	
	// init2
	await _zeitbild.conf.init(
		args["conf_path"]
	);
	lib_plankton.log.set_main_logger(
		_zeitbild.conf.get().log.map(
			(log_output : any) => {
				switch (log_output.kind) {
					case "stdout": {
						return {
							"kind": "minlevel",
							"data": {
								"core": {
									"kind": "std",
									"data": {
										"target": "stdout",
										"format": lib_plankton.call.distinguish(
											{
												"kind": log_output.data.format,
												"data": null,
											},
											{
												"jsonl": () => ({
													"kind": "jsonl",
													"data": {
														"structured": false,
													}
												}),
												"jsonl_structured": () => ({
													"kind": "jsonl",
													"data": {
														"structured": true,
													}
												}),
												"human_readable": () => ({
													"kind": "human_readable",
													"data": {
													}
												}),
											}
										),
									}
								},
								"threshold": log_output.data.threshold,
							}
						};
						break;
					}
					case "file": {
						return {
							"kind": "minlevel",
							"data": {
								"core": {
									"kind": "file",
									"data": {
										"path": log_output.data.path,
										"format": lib_plankton.call.distinguish(
											{
												"kind": log_output.data.format,
												"data": null,
											},
											{
												"jsonl": () => ({
													"kind": "jsonl",
													"data": {
														"structured": false,
													}
												}),
												"jsonl_structured": () => ({
													"kind": "jsonl",
													"data": {
														"structured": true,
													}
												}),
												"human_readable": () => ({
													"kind": "human_readable",
													"data": {
													}
												}),
											}
										),
									}
								},
								"threshold": log_output.data.threshold,
							}
						};
						break;
					}
					default: {
						throw (new Error("unhandled"));
						break;
					}
				}
			}
		)
	);
	{
		_zeitbild.cache_regular = lib_plankton.cache.make<any>();
		await lib_plankton.cache.init(_zeitbild.cache_regular);
	}
	{
		_zeitbild.cache_external_resources = lib_plankton.cache.make<any>();
		await lib_plankton.cache.init(_zeitbild.cache_external_resources);
	}
	{
		_zeitbild.cache_templates = lib_plankton.cache.make<any>();
		await lib_plankton.cache.init(_zeitbild.cache_templates);
	}
	
	// exec
	if (args["help"]) {
		process.stdout.write(
			arg_handler.generate_help(
				{
					"programname": "zeitbild",
					"description": "zeitbild-backend",
					"executable": "zeitbild",
				}
			)
			+
			"\n"
		);
	}
	else {
		switch (args["action"])
		{
			default:
			{
				lib_plankton.log.error(
					"main_invalid_action",
					{
						"action": args["action"],
					}
				);
				break;
			}
			case "conf-schema":
			{
				process.stdout.write(
					JSON.stringify(
						_zeitbild.conf.schema(),
						undefined,
						"\t"
					)
					+
					"\n"
				);
				break;
			}
			case "conf-expose":
			{
				process.stdout.write(
					JSON.stringify(
						_zeitbild.conf.get(),
						undefined,
						"\t"
					)
					+
					"\n"
				);
				break;
			}
			case "api-doc":
			{
				lib_plankton.log.set_main_logger([]);
				const rest_subject : lib_plankton.rest_http.type_rest = _zeitbild.api.make();
				process.stdout.write(
					JSON.stringify(
						lib_plankton.rest_http.to_oas(rest_subject),
						undefined,
						"\t"
					)
				);
				break;
			}
			case "sample":
			{
				await _zeitbild.sample.init(
					lib_plankton.json.decode(
						await lib_plankton.file.read(args.data_path)
					)
				);
				process.stdout.write("-- done\n");
				break;
			}
			case "serve":
			{
				// prepare database
				await _zeitbild.database.check();
				
				/**
				 * @todo clear old sessions
				 */
				
				await lib_plankton.session.setup(
					{
						"data_chest": (
							_zeitbild.conf.get().session_management.in_memory
							?
							lib_plankton.storage.memory.implementation_chest<lib_plankton.session.type_session>({})
							:
							lib_plankton.call.convey(
								lib_plankton.storage.sql_table_common.chest(
									{
										"database_implementation": _zeitbild.database.get_implementation(),
										"table_name": "sessions",
										"key_names": ["key"],
									}
								),
								[
									(core : any) => ({
										"setup": (input : any) => core.setup(undefined),
										"clear": () => core.clear(),
										"write": (key : any, value : any) => core.write([key], {"data": JSON.stringify(value)}),
										"delete": (key : any) => core.delete([key]),
										"read": (key : any) => core.read([key]).then((row : any) => JSON.parse(row["data"])),
										// "search": (term : any) => core.search(term).then(() => []),
										"search": (term : any) => Promise.reject(new Error("not implemented")),
									}),
								]
							)
						),
						"default_lifetime": _zeitbild.conf.get().session_management.lifetime,
						"default_prolongation": _zeitbild.conf.get().session_management.prolongation,
					}
				);
				
				await _zeitbild.auth.init();
				
				const rest_subject : lib_plankton.rest_http.type_rest = _zeitbild.api.make();
				const server : lib_plankton.server.type_subject = lib_plankton.server.make(
					async (input, metadata) => {
						const http_request : lib_plankton.http.type_request = lib_plankton.http.decode_request(input.toString());
						const http_response : lib_plankton.http.type_response = await lib_plankton.rest_http.call(
							rest_subject,
							http_request,
							{
								"checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
								// "checklevel_input": lib_plankton.api.enum_checklevel.soft,
								// "checklevel_output": lib_plankton.api.enum_checklevel.soft,
								"set_content_length": false,
							}
						);
						const output : string = lib_plankton.http.encode_response(http_response);
						return output;
					},
					{
						"host": _zeitbild.conf.get().server.host,
						"port": _zeitbild.conf.get().server.port,
						// DANGER! DANGER!
						"threshold": 0.125,
					}
				);
				
				lib_plankton.server.start(server);
				break;
			}
		}	
	}
	return Promise.resolve<void>(undefined);
}

(
	main(process.argv.slice(2))
	.then(
		() => {
		}
	)
	.catch(
		(error) => {
			// console.error(error);
			process.stderr.write(String(error) + "\n");
		}
	)
);
