import { IpcClient as TorrentIpc } from "@autoplex-api/torrent";
import { IpcConnectionError } from "@autoplex/ipc";
import { MiddlewareMethod, RouteRegisterFactory, Status, respond, } from "@autoplex/webserver";
import Application from "../../../Application";
import { torrent } from "../middleware/torrent";

export default function register(factory: RouteRegisterFactory<MiddlewareMethod<void>, Application>,
                                 app: Application)
{
	/**
	 * Fetch the torrent client instance
	 */
	const ipc = app.service<TorrentIpc>("Torrent");

	/**
	 * Register API prefix
	 */
	factory.prefix("/api/torrent", [], (factory, app) => {

		/**
		 * Get the torrent list
		 */
		factory.get("/list", async (_, reply) => {
			let torrentList = await ipc.list();
			respond(reply, Status.Ok, torrentList);
		});

		/**
		 * Fetch the details of all torrents
		 */
		factory.get("/details", async (_, reply) => {
			let details = await ipc.details();
			respond(reply, Status.Ok, details);
		});

		/**
		 * Fetch the details of a torrent
		 */
		factory.get("/details/:torrentId", [torrent], async (request, reply) => {
			let details = request.middlewareParams.torrent;
			respond(reply, Status.Ok, details);
		});

		/**
		 * Add a torrent to the client
		 */
		factory.post("/add", async (request, reply) => {
			let downloadPath = (<any>request.query)["download_path"] ?? undefined;
			let result: string[] = [];
			if (request.isMultipart()) {
				let files = request.files();
				for await (let file of files) {
					let torrentFile = await file.toBuffer();
					let infoHash = await ipc.add(torrentFile, downloadPath);
					result.push(infoHash);
				}
			} else {
				let links = (<any>request.body)?.link ?? null;
				if (links === null) {
					return respond(reply, Status.BadRequest);
				}
				for (let link of (Array.isArray(links) ? links : [links])) {
					let infoHash = await ipc.add(link, downloadPath);
					result.push(infoHash);
				}
			}
			respond(reply, Status.Ok, result);
		});

		/**
		 * Remove a torrent from the client
		 */
		factory.delete("/remove/:torrentId", [torrent], async (request, reply) => {
			let withData = (<any>request.query)["with_data"] === "1";
			let torrent = request.middlewareParams.torrent;
			try {
				ipc.remove(torrent.infoHash, withData);
			} catch(e) {
				if (e instanceof IpcConnectionError) {
					return respond(reply, Status.InternalServerError);
				}
				return respond(reply, Status.Gone);
			}
			respond(reply, Status.Ok);
		});
	});
}
