import * as grpc from "@grpc/grpc-js";
import { ServiceError } from "@grpc/grpc-js";

import * as path from "path";
import fs from "fs";
import { Buffer } from "buffer";
import { ImageToPdfOptions } from "../../../public/image";
import { IronPdfServiceClient } from "../../generated_proto/ironpdfengineproto/IronPdfService";
import { ChromeImageToPdfRequestStreamP } from "../../generated_proto/ironpdfengineproto/ChromeImageToPdfRequestStreamP";
import { PdfDocumentResultP__Output } from "../../generated_proto/ironpdfengineproto/PdfDocumentResultP";
import { chunkBuffer, handlePdfDocumentResultP__Output } from "../util";
import {
	chromePdfRenderOptionsToProto,
	imageBehaviorToProto,
	pdfPaperSizeToProto,
} from "./converter";
import { ChromePdfRenderOptionsP } from "../../generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP";
import { PdfPaperSize } from "../../../public/paper";
import { ChromeImageFilesToPdfRequestStreamP } from "../../generated_proto/ironpdfengineproto/ChromeImageFilesToPdfRequestStreamP";
import { Access } from "../../access";

export async function renderImagesBufferToPdf(
	imagesBuffer: Buffer[],
	options?: ImageToPdfOptions
): Promise<string> {
	const client: IronPdfServiceClient = await Access.ensureConnection();
	return new Promise(
		(resolve: (_: string) => void, reject: (errorMsg: string) => void) => {
			const stream: grpc.ClientWritableStream<ChromeImageToPdfRequestStreamP> =
				client.Chrome_Image_ImageToPdf(
					(
						err: ServiceError | null,
						value: PdfDocumentResultP__Output | undefined
					) => {
						if (err) {
							reject(`${err.name}/n${err.message}`);
						} else if (value) {
							handlePdfDocumentResultP__Output(
								value,
								resolve,
								reject
							);
						}
					}
				);

			const renderOption = chromePdfRenderOptionsToProto(); //default
			overridePaperSize(renderOption, options?.paperSize);

			stream.write({
				info: {
					renderOptions: renderOption,
					imageBehavior: imageBehaviorToProto(options?.imageBehavior),
				},
			});

			imagesBuffer.forEach((imageBuffer, index) => {
				chunkBuffer(imageBuffer).forEach((chunk) => {
					stream.write({
						rawImagesChunk: {
							imageIndex: index,
							rawImageChunk: chunk,
						},
					});
				});
			});
			stream.end();
		}
	);
}

function overridePaperSize(
	renderOption: ChromePdfRenderOptionsP,
	pdfPaperSize?: PdfPaperSize
) {
	if (pdfPaperSize) {
		const paperSizeSetting = pdfPaperSizeToProto(pdfPaperSize);
		if (paperSizeSetting?.widthHeight) {
			renderOption.paperSize = paperSizeSetting.paperSizeP;
			renderOption.customPaperWidth = paperSizeSetting.widthHeight.width;
			renderOption.customPaperHeight =
				paperSizeSetting.widthHeight.height;
		} else if (paperSizeSetting) {
			renderOption.paperSize = paperSizeSetting.paperSizeP;
		}
	}
}

export async function renderImagesFilesToPdf(
	imagesBufferFilePath: string[],
	options?: ImageToPdfOptions
): Promise<string> {
	const client: IronPdfServiceClient = await Access.ensureConnection();
	return new Promise(
		(resolve: (_: string) => void, reject: (errorMsg: string) => void) => {
			const stream: grpc.ClientWritableStream<ChromeImageFilesToPdfRequestStreamP> =
				client.Chrome_Image_ImageFilesToPdf(
					(
						err: ServiceError | null,
						value: PdfDocumentResultP__Output | undefined
					) => {
						if (err) {
							reject(`${err.name}/n${err.message}`);
						} else if (value) {
							handlePdfDocumentResultP__Output(
								value,
								resolve,
								reject
							);
						}
					}
				);

			const renderOption = chromePdfRenderOptionsToProto(); //default
			overridePaperSize(renderOption, options?.paperSize);

			stream.write({
				info: {
					renderOptions: renderOption,
					imageBehavior: imageBehaviorToProto(options?.imageBehavior),
				},
			});

			imagesBufferFilePath.forEach((imagePath, index) => {
				const fileType = path.extname(imagePath);

				const buffer = fs.readFileSync(imagePath);
				chunkBuffer(buffer).forEach((chunk) => {
					stream.write({
						rawImagesFileChunk: {
							fileType: fileType,
							imageIndex: index,
							rawImageChunk: chunk,
						},
					});
				});
			});

			stream.end();
		}
	);
}
