import { hexToRgb } from './functions';
import { Core } from '@pdftron/webviewer';
import PDFDoc = Core.PDFNet.PDFDoc;
import {
    WATERMARK_HORIZONTAL_ALIGNMENTS,
    WATERMARK_VERTICAL_ALIGNMENTS,
    WatermarkHorizontalAlignment,
    WatermarkVerticalAlignment,
} from '@red/domain';

const HORIZONTAL_TEXT_ALIGNMENT_MATRIX = [
    [-1, 0, 1],
    [-1, 0, 1],
    [-1, 0, 1],
];

const VERTICAL_TEXT_ALIGNMENT_MATRIX = [
    [1, 1, 1],
    [0, 0, 0],
    [-1, -1, -1],
];

const DIAGONAL_TEXT_ALIGNMENT_MATRIX = [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 0],
];

async function createPageSet(pdfNet: typeof Core.PDFNet, pages: number[]) {
    const pageSet = await pdfNet.PageSet.create();
    for (const page of pages) {
        if (page > 0) {
            await pageSet.addPage(page);
        }
    }
    return pageSet;
}

function convertFont(pdfNet: typeof Core.PDFNet, type: string): number {
    switch (type) {
        case 'times-new-roman':
            return pdfNet.Font.StandardType1Font.e_times_roman;
        case 'helvetica':
            return pdfNet.Font.StandardType1Font.e_helvetica;
        case 'courier':
            return pdfNet.Font.StandardType1Font.e_courier;
    }
    return pdfNet.Font.StandardType1Font.e_helvetica;
}

export async function clearStamps(document: PDFDoc, pdfNet: typeof Core.PDFNet, pages: number[], licenseKey: string) {
    await pdfNet.runWithCleanup(async () => {
        await document.lock();
        const pageSet = await createPageSet(pdfNet, pages);
        await pdfNet.Stamper.deleteStamps(document, pageSet);
    }, licenseKey);
}

export async function stampPDFPage(
    document: PDFDoc,
    pdfNet: typeof Core.PDFNet,
    text: string,
    fontSize: number,
    fontType: string,
    orientation: 'DIAGONAL' | 'HORIZONTAL' | 'VERTICAL' | 'TOP_LEFT',
    horizontalTextAlignment: WatermarkHorizontalAlignment,
    verticalTextAlignment: WatermarkVerticalAlignment,
    opacity: number,
    color: string,
    pages: number[],
    licenseKey: string,
) {
    await pdfNet.runWithCleanup(async () => {
        await document.lock();

        const pageSet = await createPageSet(pdfNet, pages);
        await pdfNet.Stamper.deleteStamps(document, pageSet);

        const { b, g, r } = hexToRgb(color);

        const stamper = await pdfNet.Stamper.create(pdfNet.Stamper.SizeType.e_font_size, fontSize, 0);
        await stamper.setFontColor(await pdfNet.ColorPt.init(r / 255, g / 255, b / 255));
        await stamper.setOpacity(opacity / 100);

        let horizontalAlignment: number;
        let verticalAlignment: number;

        switch (horizontalTextAlignment) {
            case WATERMARK_HORIZONTAL_ALIGNMENTS.LEFT:
                horizontalAlignment = -1;
                break;
            case WATERMARK_HORIZONTAL_ALIGNMENTS.CENTER:
                horizontalAlignment = 0;
                break;
            case WATERMARK_HORIZONTAL_ALIGNMENTS.RIGHT:
                horizontalAlignment = 1;
                break;
        }

        switch (verticalTextAlignment) {
            case WATERMARK_VERTICAL_ALIGNMENTS.TOP:
                verticalAlignment = 1;
                break;
            case WATERMARK_VERTICAL_ALIGNMENTS.CENTER:
                verticalAlignment = 0;
                break;
            case WATERMARK_VERTICAL_ALIGNMENTS.BOTTOM:
                verticalAlignment = -1;
                break;
        }

        await stamper.setAlignment(horizontalAlignment, verticalAlignment);

        verticalAlignment = reverseNumberSign(verticalAlignment);

        switch (orientation) {
            case 'VERTICAL':
                await stamper.setRotation(-90);
                await stamper.setTextAlignment(VERTICAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
                await stamper.setPosition(10, 20);
                break;
            case 'HORIZONTAL':
                await stamper.setTextAlignment(HORIZONTAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
                await stamper.setPosition(20, 10);
                break;
            case 'DIAGONAL':
            default:
                await stamper.setRotation(-45);
                await stamper.setTextAlignment(DIAGONAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
                await stamper.setPosition(20, 10);
        }

        const initialFont = await pdfNet.Font.create(document, convertFont(pdfNet, fontType));
        // in case there are japanese characters in the text, we add them to the font
        const fontWithAllTextChars = await pdfNet.Font.createFromFontDescriptor(document, initialFont, text);
        await stamper.setFont(fontWithAllTextChars);
        await stamper.stampText(document, text, pageSet);
    }, licenseKey);
}

function reverseNumberSign(n: number): number {
    return n - n * 2;
}
