import { effect, inject, Injectable, Signal, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';
import { log } from '@iqser/common-ui/lib/utils';
import { Core } from '@pdftron/webviewer';
import { RotationType, RotationTypes } from '@red/domain';
import { UserPreferenceService } from '@users/user-preference.service';
import { NGXLogger } from 'ngx-logger';
import { BehaviorSubject, fromEvent, Observable } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
import { AnnotationToolNames } from '../utils/constants';
import { stopAndPrevent, stopAndPreventIfNotAllowed } from '../utils/functions';
import { PdfViewer } from './pdf-viewer.service';
import Color = Core.Annotations.Color;
import DocumentViewer = Core.DocumentViewer;
import Quad = Core.Math.Quad;

@Injectable()
export class REDDocumentViewer {
    #document: DocumentViewer;
    readonly #loaded = signal(false);
    readonly #pageComplete = signal<unknown | undefined>(undefined);
    readonly #logger = inject(NGXLogger);
    readonly #userPreferenceService = inject(UserPreferenceService);
    readonly #pdf = inject(PdfViewer);
    readonly #activatedRoute = inject(ActivatedRoute);
    readonly loaded$: Observable<boolean>;
    keyUp$: Observable<KeyboardEvent>;
    readonly selectedText$ = new BehaviorSubject('');
    readonly loaded: Signal<boolean>;
    readonly pageComplete: Signal<unknown | undefined>;

    constructor() {
        this.loaded = this.#loaded.asReadonly();
        this.loaded$ = toObservable(this.#loaded);
        this.pageComplete = this.#pageComplete.asReadonly();

        effect(() => {
            const viewerElement = document.getElementById('viewer');
            if (!viewerElement) {
                return;
            }

            if (this.loaded()) {
                this.#logger.info('[PDF] Show viewer');
                viewerElement.style.visibility = 'visible';
            } else {
                this.#logger.info('[PDF] Hide viewer');
                viewerElement.style.visibility = 'hidden';
            }
        });
    }

    get selectedText() {
        return this.selectedText$.value;
    }

    get PDFDoc() {
        return this.document?.getPDFDoc();
    }

    get document() {
        return this.#document.getDocument();
    }

    get currentPageRotation() {
        return this.document?.getPageRotation(this.#document.getCurrentPage());
    }

    get #keyUp$() {
        return fromEvent<KeyboardEvent>(this.#document, 'keyUp').pipe(
            tap(stopAndPreventIfNotAllowed),
            filter($event => {
                if (($event.target as HTMLElement)?.tagName?.toLowerCase() === 'input') {
                    if ($event.key === 'Escape') {
                        return true;
                    }
                }
                return ($event.target as HTMLElement)?.tagName?.toLowerCase() !== 'input';
            }),
            filter($event => $event.key.startsWith('Arrow') || ['f', 'h', 'H', 'Escape'].includes($event.key)),
            tap<KeyboardEvent>(stopAndPrevent),
            log('[PDF] Keyboard shortcut'),
        );
    }

    clearSelection() {
        this.#document.clearSelection();
        this.#pdf.disable('textPopup');
    }

    close() {
        const closeAction = async () => {
            this.#logger.info('[PDF] Closing document');
            this.#document.closeDocument();
            this.#pdf.closeCompareMode();
            await this.#pdf.instance.UI.closeDocument();
        };

        this.#pdf.runWithCleanup(closeAction).then();
    }

    updateTooltipsVisibility(): void {
        const current = this.#userPreferenceService.getFilePreviewTooltipsPreference();
        this.#pdf.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false));
    }

    init(document: DocumentViewer) {
        this.#document = document;
        this.#listenForDocEvents();
        this.keyUp$ = this.#keyUp$;
    }

    async blob() {
        const data = await this.document.getFileData();
        return new Blob([new Uint8Array(data)], { type: 'application/pdf' });
    }

    setRectangleToolStyles(color: Color) {
        this.#document.getTool(AnnotationToolNames.AnnotationCreateRectangle).setStyles({
            StrokeThickness: 2,
            StrokeColor: color,
            FillColor: color,
            Opacity: 0.6,
        });
    }

    getHeight(page: number) {
        try {
            return this.#document.getPageHeight(page);
        } catch {
            // might throw Error: getPageHeight was called before the 'documentLoaded' event
            return 0;
        }
    }

    refreshAndUpdateView(visiblePages?: number[]) {
        const currentPage = this.#document.getCurrentPage();
        this.#document.refreshAll();
        if (visiblePages) {
            this.#document.updateView(visiblePages, currentPage);
        } else {
            this.#document.updateView();
        }
    }

    resetRotation(pages: number | number[] | string | string[]) {
        if (!(pages instanceof Array)) {
            pages = [Number(pages)];
        }

        pages.forEach(page => this.#document.setRotation(0, Number(page)));
    }

    rotate(rotation: RotationType, page = this.#pdf.currentPage()) {
        if (rotation === RotationTypes.LEFT) {
            this.#document.rotateCounterClockwise(page);
        } else {
            this.#document.rotateClockwise(page);
        }
    }

    #listenForDocEvents() {
        this.#document.addEventListener('textSelected', (quads: Quad, selectedText: string, pageNumber: number) => {
            this.selectedText$.next(selectedText);
            this.#disableTextPopupIfCompareMode(pageNumber);
        });

        this.#document.addEventListener('pageComplete', event => {
            setTimeout(() => {
                this.#pageComplete.set(event);
            }, 300);
        });

        this.#document.addEventListener('documentUnloaded', () => {
            this.#logger.info('[PDF] Document unloaded');
            this.#loaded.set(false);
        });

        this.#document.addEventListener('documentLoaded', () => {
            this.#logger.info('[PDF] Document loaded');

            this.#pdf.runWithCleanup(() => {
                this.#flattenAnnotations().then();
                this.#setCurrentPage();
                this.#setInitialDisplayMode();
                this.updateTooltipsVisibility();
            });

            this.#loaded.set(true);
        });
    }

    async #flattenAnnotations() {
        const pdfDoc = await this.PDFDoc;
        await pdfDoc.flattenAnnotations(false);
    }

    #disableTextPopupIfCompareMode(pageNumber: number) {
        if (this.#pdf.isCompareMode() && pageNumber % 2 === 0) {
            return this.#pdf.disable('textPopup');
        }

        this.#pdf.enable('textPopup');
    }

    #setCurrentPage() {
        const currentDocPage = this.#activatedRoute.snapshot.queryParamMap.get('page');
        this.#pdf.navigateTo(currentDocPage ?? 1);
    }

    #setInitialDisplayMode() {
        this.#pdf.instance.UI.setFitMode('FitPage');
        const displayModeManager = this.#document.getDisplayModeManager();
        const instanceDisplayMode = displayModeManager.getDisplayMode();
        instanceDisplayMode.mode = this.#pdf.isCompareMode() ? 'Facing' : 'Single';
        displayModeManager.setDisplayMode(instanceDisplayMode);
    }
}
