import { Injectable } from '@angular/core';
import { List } from '@iqser/common-ui/lib/utils';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Core } from '@pdftron/webviewer';
import { IRectangle, ISectionRectangle, SuperTypes } from '@red/domain';
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { hexToRgb } from '@utils/functions';
import { BoundingBox, Table } from '../../file-preview/services/tables.service';
import { REDAnnotationManager } from './annotation-manager.service';
import { REDDocumentViewer } from './document-viewer.service';
import { PdfViewer } from './pdf-viewer.service';
import Annotation = Core.Annotations.Annotation;
import Quad = Core.Math.Quad;

const DEFAULT_TEXT_ANNOTATION_OPACITY = 1;
const DEFAULT_REMOVED_ANNOTATION_OPACITY = 0.2;

export function getSectionRectangle(box: BoundingBox): ISectionRectangle {
    return {
        topLeft: {
            x: box.x,
            y: box.y,
        },
        width: box.width,
        height: box.height,
    };
}

@Injectable()
export class AnnotationDrawService {
    constructor(
        private readonly _annotationManager: REDAnnotationManager,
        private readonly _pdf: PdfViewer,
        private readonly _documentViewer: REDDocumentViewer,
        private readonly _defaultColorsService: DefaultColorsService,
    ) {}

    async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
        try {
            return this._pdf.runWithCleanup(() => this.#draw(annotations, hideSkipped, dossierTemplateId));
        } catch (e) {
            console.error(e);
        }
    }

    convertColor(hexColor: string) {
        return this._pdf.color(hexToRgb(hexColor));
    }

    annotationToQuads(annotation: Annotation) {
        const x1 = annotation.getRect().x1;
        const y1 = annotation.getRect().y1 + annotation.getRect().getHeight();

        const x2 = annotation.getRect().x1 + annotation.getRect().getWidth();
        const y2 = annotation.getRect().y1 + annotation.getRect().getHeight();

        const x3 = annotation.getRect().x1 + annotation.getRect().getWidth();
        const y3 = annotation.getRect().y1;

        const x4 = annotation.getRect().x1;
        const y4 = annotation.getRect().y1;

        return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
    }

    async drawTables(tables: Table[], page: number, dossierTemplateId: string) {
        const sections: Core.Annotations.RectangleAnnotation[] = [];
        tables.forEach(table => {
            const section = this.#computeSection(page, getSectionRectangle(table.boundingBox), dossierTemplateId);
            if (table.experimental) {
                section.StrokeColor = this.convertColor('#800080');
            } else {
                section.StrokeColor = this.convertColor('#dc2626');
            }
            sections.push(section);
            table.cellsPerRow
                .flatMap(row => row)
                .forEach(row => {
                    const cellSection = this.#computeSection(page, getSectionRectangle(row.boundingBox), dossierTemplateId);
                    if (table.experimental) {
                        cellSection.StrokeColor = this.convertColor('#800080');
                    } else {
                        cellSection.StrokeColor = this.convertColor('#dc2626');
                    }
                    sections.push(cellSection);
                });
        });

        await this._annotationManager.add(sections);
    }

    async #draw(annotationWrappers: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
        const totalPages = this._pdf.totalPages();
        const annotations = annotationWrappers
            ?.map(annotation => this.#computeAnnotation(annotation, hideSkipped, totalPages, dossierTemplateId))
            .filterTruthy();
        if (!this._documentViewer.loaded()) {
            return;
        }
        await this._annotationManager.add(annotations);
    }

    #computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dossierTemplateId: string) {
        const rectangleAnnot = this._pdf.rectangle();
        const pageHeight = this._documentViewer.getHeight(pageNumber);
        const rectangle: IRectangle = {
            topLeft: sectionRectangle.topLeft,
            page: pageNumber,
            height: sectionRectangle.height,
            width: sectionRectangle.width,
        };
        rectangleAnnot.PageNumber = pageNumber;
        rectangleAnnot.X = rectangle.topLeft.x - 1;
        rectangleAnnot.Y = pageHeight - (rectangle.topLeft.y + rectangle.height) - 1;
        rectangleAnnot.Width = rectangle.width + 2;
        rectangleAnnot.Height = rectangle.height + 2;
        rectangleAnnot.ReadOnly = true;
        rectangleAnnot.StrokeColor = this.convertColor(this._defaultColorsService.getColor(dossierTemplateId, 'analysisColor'));
        rectangleAnnot.StrokeThickness = 1;

        return rectangleAnnot;
    }

    #computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dossierTemplateId: string) {
        const pageNumber = this._pdf.isCompareMode() ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
        if (pageNumber > totalPages) {
            // skip imported annotations from files that have more pages than the current one
            return;
        }

        if (annotationWrapper.superType === SuperTypes.TextHighlight) {
            const rectangleAnnot = this._pdf.rectangle();
            const pageHeight = this._documentViewer.getHeight(pageNumber);
            const rectangle: IRectangle = annotationWrapper.positions[0];
            rectangleAnnot.PageNumber = pageNumber;
            rectangleAnnot.X = rectangle.topLeft.x;
            rectangleAnnot.Y = pageHeight - (rectangle.topLeft.y + rectangle.height);
            rectangleAnnot.Width = rectangle.width;
            rectangleAnnot.Height = rectangle.height;
            rectangleAnnot.ReadOnly = true;
            rectangleAnnot.StrokeColor = this.convertColor(annotationWrapper.color);
            rectangleAnnot.StrokeThickness = 1;
            rectangleAnnot.Id = annotationWrapper.id;

            return rectangleAnnot;
        }

        const annotation = this._pdf.textHighlight();
        annotation.Quads = this.#rectanglesToQuads(annotationWrapper.positions, pageNumber);
        annotation.Opacity = annotationWrapper.isChangeLogRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
        annotation.setContents(annotationWrapper.content);
        annotation.PageNumber = pageNumber;
        annotation.StrokeColor = this.convertColor(annotationWrapper.color);
        annotation.Id = annotationWrapper.id;
        annotation.ReadOnly = true;

        const isOCR = annotationWrapper.isOCR && !annotationWrapper.isSuggestionResize;
        if (isOCR && !this._annotationManager.isHidden(annotationWrapper.id)) {
            this._annotationManager.addToHidden(annotationWrapper.id);
        }
        annotation.Hidden =
            annotationWrapper.isChangeLogRemoved ||
            (hideSkipped && annotationWrapper.isSkipped) ||
            this._annotationManager.isHidden(annotationWrapper.id);
        annotation.setCustomData('redact-manager', 'true');
        annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation));
        annotation.setCustomData('suggestion', String(annotationWrapper.isSuggestion));
        annotation.setCustomData('suggestionAdd', String(annotationWrapper.isSuggestionAdd));
        annotation.setCustomData('suggestionAddToFalsePositive', String(annotationWrapper.isSuggestionAddToFalsePositive));
        annotation.setCustomData('suggestionRemove', String(annotationWrapper.isSuggestionRemove));
        annotation.setCustomData('suggestionRecategorizeImage', String(annotationWrapper.isSuggestionRecategorizeImage));
        annotation.setCustomData('suggestionForceHint', String(annotationWrapper.isSuggestionForceHint));
        annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
        annotation.setCustomData('notSignatureImage', String(annotationWrapper.isNotSignatureImage));
        annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
        annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved));
        annotation.setCustomData('opacity', String(annotation.Opacity));

        const redactionColor = this._defaultColorsService.getColor(dossierTemplateId, 'previewColor');
        annotation.setCustomData('redactionColor', String(redactionColor));
        annotation.setCustomData('annotationColor', String(annotationWrapper.color));

        const appliedRedactionColor = this._defaultColorsService.getColor(dossierTemplateId, 'appliedRedactionColor');
        annotation.setCustomData('appliedRedactionColor', String(appliedRedactionColor));

        return annotation;
    }

    #rectanglesToQuads(positions: IRectangle[], pageNumber: number): Quad[] {
        const pageHeight = this._documentViewer.getHeight(pageNumber);
        return positions.map(p => this.#rectangleToQuad(p, pageHeight));
    }

    #rectangleToQuad(rectangle: IRectangle, pageHeight: number): Quad {
        const x1 = rectangle.topLeft.x;
        const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height);

        const x2 = rectangle.topLeft.x + rectangle.width;
        const y2 = pageHeight - (rectangle.topLeft.y + rectangle.height);

        const x3 = rectangle.topLeft.x + rectangle.width;
        const y3 = pageHeight - rectangle.topLeft.y;

        const x4 = rectangle.topLeft.x;
        const y4 = pageHeight - rectangle.topLeft.y;

        return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
    }
}
