import * as grpc from "@grpc/grpc-js";
import {ServiceError} from "@grpc/grpc-js";
import {IronPdfServiceClient} from "../../generated_proto/ironpdfengineproto/IronPdfService";
import {Access} from "../../access";
import {
	PdfiumPdfDocumentConstructorStreamP
} from "../../generated_proto/ironpdfengineproto/PdfiumPdfDocumentConstructorStreamP";
import {PdfDocumentResultP__Output} from "../../generated_proto/ironpdfengineproto/PdfDocumentResultP";
import {chunkBuffer, handlePdfDocumentResultP__Output} from "../util";
import {ChangeTrackingModes, SaveOptions} from "../../../public/types";
import {BytesResultStreamP__Output} from "../../generated_proto/ironpdfengineproto/BytesResultStreamP";
import {
	PdfiumGetBinaryDataRequestStreamP
} from "../../generated_proto/ironpdfengineproto/PdfiumGetBinaryDataRequestStreamP";

export async function openPdfFileBuffer(
	buffer: Buffer,
	option?: { userPassword?: string | undefined; ownerPassword?: string | undefined, trackChanges?: ChangeTrackingModes | undefined } | undefined
): Promise<string> {
	const client: IronPdfServiceClient = await Access.ensureConnection();
	return new Promise(
		(resolve: (_: string) => void, reject: (errorMsg: string) => void) => {
			const stream: grpc.ClientWritableStream<PdfiumPdfDocumentConstructorStreamP> =
				client.Pdfium_FromBytes(
					(
						err: ServiceError | null,
						value: PdfDocumentResultP__Output | undefined
					) => {
						if (err) {
							reject(`${err.name}/n${err.message}`);
						} else if (value) {
							handlePdfDocumentResultP__Output(
								value,
								resolve,
								reject
							);
						}
					}
				);

			stream.write({
				info: {
					ownerPassword: option?.ownerPassword ?? "",
					userPassword: option?.userPassword ?? "",
					trackChanges: option?.trackChanges ?? ChangeTrackingModes.AutoChangeTracking
				},
			});

			chunkBuffer(buffer).forEach((chunk) => {
				stream.write({ pdfBytesChunk: chunk });
			});

			stream.end();
		}
	);
}

export async function getBinaryData(
	pdfDocumentId: string,
	saveOptions?: SaveOptions | undefined
): Promise<Buffer> {
	const client: IronPdfServiceClient = await Access.ensureConnection();

	return new Promise(
		(resolve: (_: Buffer) => void, reject: (errorMsg: string) => void) => {
			const stream: grpc.ClientDuplexStream<
				PdfiumGetBinaryDataRequestStreamP,
				BytesResultStreamP__Output
			> = client.Pdfium_GetBinaryData();

			//response handler
			const buffers: Buffer[] = [];
			stream.on("data", (data: BytesResultStreamP__Output) => {
				if (data.exception) {
					reject(
						`${data.exception.message}/n${data.exception.remoteStackTrace}`
					);
				} else if (data.resultChunk) {
					buffers.push(data.resultChunk);
				}
			});

			stream.on("end", () => {
				resolve(Buffer.concat(buffers));
			});

			//sent request

			//info
			stream.write({
				info: {
					document: { documentId: pdfDocumentId },
					isWatermarked: false,
					isIncremental: saveOptions?.incremental ?? false,
				},
			});

			//not working for now
			// // signatures
			// const collection = saveOptions?.digitalSignatures?.map(
			// 	(digitalSignature, signatureIndex) => {
			// 		const pdfiumPdfSignatureP: PdfiumPdfSignatureP = {
			// 			index: signatureIndex,
			// 			password: digitalSignature.certificatePassword,
			// 			timestampUrl: digitalSignature.timeStampUrl,
			// 		};
			// 		return pdfiumPdfSignatureP;
			// 	}
			// );
			// stream.write({ signatures: { signature: collection } });

			// //rawSignaturesChunk
			// saveOptions?.digitalSignatures?.forEach(
			// 	(digitalSignature, signatureIndex) => {
			// 		const buf = digitalSignature.certificatePath
			// 			? fs.readFileSync(digitalSignature.certificatePath)
			// 			: digitalSignature.certificateBuffer;
			//
			// 		if (buf) {
			// 			chunkBuffer(buf).forEach((chunk) => {
			// 				const pdfiumRawSignatureChunkWithIndexP: PdfiumRawSignatureChunkWithIndexP =
			// 					{
			// 						rawSignatureChunk: chunk,
			// 						signatureIndex,
			// 					};
			// 				stream.write({
			// 					rawSignaturesChunk:
			// 						pdfiumRawSignatureChunkWithIndexP,
			// 				});
			// 			});
			// 		}
			// 	}
			// );
			//request finished
			stream.end();
		}
	);
}

export async function disposePdf(pdfDocumentId: string): Promise<void> {
	const client: IronPdfServiceClient = await Access.ensureConnection();

	return new Promise(
		(resolve: () => void, reject: (errorMsg: string) => void) => {
			client.pdfiumDispose(
				{ documentId: pdfDocumentId },
				(err, value) => {
					if (err) {
						reject(`${err.name}/n${err.message}`);
					} else if (value) {
						//ignore result
						resolve();
					}
				}
			);
		}
	);
}
