import { inject, Injectable, NgZone } from '@angular/core';
import { getConfig, HelpModeService, IqserPermissionsService, isIqserDevMode } from '@iqser/common-ui';
import { BASE_HREF_FN } from '@iqser/common-ui/lib/utils';
import { TranslateService } from '@ngx-translate/core';
import { IHeaderElement, RotationTypes } from '@red/domain';
import { FilesMapService } from '@services/files/files-map.service';
import { Roles } from '@users/roles';
import { fromEvent, merge, Observable, Subject } from 'rxjs';
import { filter, map, tap } from 'rxjs/operators';
import { HeaderElements, HeaderElementType } from '../../file-preview/utils/constants';
import { ROTATION_ACTION_BUTTONS, ROTATION_BUTTONS, ViewerEvents } from '../utils/constants';
import { ViewerEvent, VisibilityChangedEvent } from '../utils/types';
import { REDDocumentViewer } from './document-viewer.service';
import { LayersService } from './layers.service';
import { PageRotationService } from './page-rotation.service';
import { PdfViewer } from './pdf-viewer.service';
import { ReadableRedactionsService } from './readable-redactions.service';
import { TooltipsService } from './tooltips.service';

const divider: IHeaderElement = {
    type: 'divider',
};

@Injectable()
export class ViewerHeaderService {
    readonly #convertPath = inject(BASE_HREF_FN);
    readonly #iqserPermissionService = inject(IqserPermissionsService);
    readonly #isDocumine = getConfig().IS_DOCUMINE;
    #buttons: Map<HeaderElementType, IHeaderElement>;
    readonly #panels = ['thumbnailsPanel', 'outlinesPanel', 'layersPanel', 'signaturePanel'];
    #docBeforeCompare: Blob;
    readonly #events$ = new Subject<ViewerEvent>();
    readonly #config = new Map<HeaderElementType, boolean>([
        [HeaderElements.SHAPE_TOOL_GROUP_BUTTON, !this.#iqserPermissionService.has(Roles.getRss)],
        [HeaderElements.TOGGLE_TOOLTIPS, true],
        [HeaderElements.TOGGLE_LAYERS, isIqserDevMode() || (this.#isDocumine && this.#iqserPermissionService.has(Roles.rules.write))],
        [HeaderElements.TOGGLE_READABLE_REDACTIONS, false],
        [HeaderElements.LOAD_ALL_ANNOTATIONS, false],
        [HeaderElements.COMPARE_BUTTON, !this.#isDocumine],
        [HeaderElements.CLOSE_COMPARE_BUTTON, false],
        [HeaderElements.ROTATE_LEFT_BUTTON, false],
        [HeaderElements.ROTATE_RIGHT_BUTTON, false],
        [HeaderElements.APPLY_ROTATION, false],
        [HeaderElements.DISCARD_ROTATION, false],
    ]);
    readonly events$: Observable<ViewerEvent>;
    toggleLoadAnnotations$: Observable<boolean>;

    constructor(
        private readonly _filesMapService: FilesMapService,
        private readonly _translateService: TranslateService,
        private readonly _pdf: PdfViewer,
        private readonly _documentViewer: REDDocumentViewer,
        private readonly _rotationService: PageRotationService,
        private readonly _tooltipsService: TooltipsService,
        private readonly _layersService: LayersService,
        private readonly _readableRedactionsService: ReadableRedactionsService,
        private readonly _ngZone: NgZone,
        private readonly _helpModeService: HelpModeService,
    ) {
        this.events$ = this.#events$.asObservable();
    }

    get expandedPanelEvent$() {
        const visibilityEvent$ = fromEvent(this._pdf.instance?.UI, this._pdf.instance.UI?.Events.VISIBILITY_CHANGED);
        return visibilityEvent$.pipe(
            map<CustomEvent, VisibilityChangedEvent>(event => event.detail),
            filter(event => this.#panels.includes(event.element)),
            map(event => event.isVisible),
        );
    }

    get #rectangle(): IHeaderElement {
        return {
            type: 'toolGroupButton',
            toolGroup: 'rectangleTools',
            dataElement: HeaderElements.SHAPE_TOOL_GROUP_BUTTON,
            img: this.#convertPath('/assets/icons/general/pdftron-rectangle.svg'),
            title: 'annotation.rectangle',
        };
    }

    get #toggleTooltips(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.TOGGLE_TOOLTIPS,
            dataElement: HeaderElements.TOGGLE_TOOLTIPS,
            title: this._tooltipsService.toggleTooltipsBtnTitle,
            img: this._tooltipsService.toggleTooltipsBtnIcon,
            onClick: () => this._ngZone.run(() => this._tooltipsService.toggleTooltips()),
        };
    }

    get #toggleLayers(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.TOGGLE_LAYERS,
            dataElement: HeaderElements.TOGGLE_LAYERS,
            title: this._layersService.toggleLayersBtnTitle,
            img: this._layersService.toggleLayersBtnIcon,
            onClick: () => this._ngZone.run(() => this._layersService.toggleLayers()),
        };
    }

    get #toggleReadableRedactions(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.TOGGLE_READABLE_REDACTIONS,
            dataElement: HeaderElements.TOGGLE_READABLE_REDACTIONS,
            title: this._readableRedactionsService.toggleReadableRedactionsBtnTitle,
            img: this._readableRedactionsService.toggleReadableRedactionsBtnIcon,
            onClick: () => this._ngZone.run(() => this._readableRedactionsService.toggleReadableRedactions()),
        };
    }

    get #loadAllAnnotations(): IHeaderElement {
        return {
            type: 'actionButton',
            title: this._translateService.instant('viewer-header.load-all-annotations'),
            img: this.#convertPath('/assets/icons/general/pdftron-action-load-all-annotations.svg'),
            onClick: () => this._ngZone.run(() => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS })),
            dataElement: HeaderElements.LOAD_ALL_ANNOTATIONS,
        };
    }

    get #closeCompare(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.CLOSE_COMPARE_BUTTON,
            dataElement: HeaderElements.CLOSE_COMPARE_BUTTON,
            img: this.#convertPath('/assets/icons/general/pdftron-action-close-compare.svg'),
            title: 'Leave Compare Mode',
            onClick: () => this._ngZone.run(() => this.#closeCompareMode()),
        };
    }

    get #rotateLeft(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.ROTATE_LEFT_BUTTON,
            dataElement: HeaderElements.ROTATE_LEFT_BUTTON,
            img: this.#convertPath('/assets/icons/general/rotate-left.svg'),
            title: 'Rotate page left',
            onClick: () =>
                this._ngZone.run(() => {
                    this._rotationService.addRotation(RotationTypes.LEFT);
                    this.#toggleRotationActionButtons();
                }),
        };
    }

    get #applyRotation(): IHeaderElement {
        return {
            type: 'customElement',
            dataElement: HeaderElements.APPLY_ROTATION,
            render: () => {
                const paragraph = document.createElement('p');
                paragraph.innerText = this._translateService.instant('page-rotation.apply');
                paragraph.style.cssText = `
                        font-size: 11px;
                        font-weight: 600;
                        color: #DD4D50;
                        cursor: pointer;
                        margin: 0 12px;
                    `;
                paragraph.addEventListener('click', () =>
                    this._ngZone.run(async () => {
                        await this._rotationService.applyRotation();
                        this.disable(ROTATION_ACTION_BUTTONS);
                    }),
                );
                return paragraph;
            },
        };
    }

    get #discardRotationButton(): IHeaderElement {
        return {
            type: 'customElement',
            dataElement: HeaderElements.DISCARD_ROTATION,
            render: () => {
                const paragraph = document.createElement('p');
                paragraph.innerText = this._translateService.instant('page-rotation.discard');
                paragraph.style.cssText = `
                        font-size: 11px;
                        font-weight: 600;
                        color: #283241;
                        cursor: pointer;
                        opacity: 0.7;
                    `;
                paragraph.addEventListener('click', () => this._ngZone.run(() => this.#discardRotation()));
                return paragraph;
            },
        };
    }

    get #rotateRight(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.ROTATE_RIGHT_BUTTON,
            dataElement: HeaderElements.ROTATE_RIGHT_BUTTON,
            img: this.#convertPath('/assets/icons/general/rotate-right.svg'),
            title: 'Rotate page right',
            onClick: () =>
                this._ngZone.run(() => {
                    this._rotationService.addRotation(RotationTypes.RIGHT);
                    this.#toggleRotationActionButtons();
                }),
        };
    }

    get #compare(): IHeaderElement {
        return {
            type: 'actionButton',
            element: HeaderElements.COMPARE_BUTTON,
            dataElement: HeaderElements.COMPARE_BUTTON,
            img: this.#convertPath('/assets/icons/general/pdftron-action-compare.svg'),
            title: 'Compare',
            onClick: () =>
                this._ngZone.run(async () => {
                    document.getElementById('compareFileInput').click();
                    this.#docBeforeCompare = await this._documentViewer.blob();
                }),
        };
    }

    get #toggleLoadAnnotations$() {
        return merge(this.expandedPanelEvent$, this._helpModeService.isHelpModeActive$).pipe(
            tap(enable =>
                enable ? this.enable([HeaderElements.LOAD_ALL_ANNOTATIONS]) : this.disable([HeaderElements.LOAD_ALL_ANNOTATIONS]),
            ),
        );
    }

    init(): void {
        this.#buttons = new Map([
            [HeaderElements.SHAPE_TOOL_GROUP_BUTTON, this.#rectangle],
            [HeaderElements.ROTATE_LEFT_BUTTON, this.#rotateLeft],
            [HeaderElements.ROTATE_RIGHT_BUTTON, this.#rotateRight],
            [HeaderElements.APPLY_ROTATION, this.#applyRotation],
            [HeaderElements.DISCARD_ROTATION, this.#discardRotationButton],
            [HeaderElements.TOGGLE_TOOLTIPS, this.#toggleTooltips],
            [HeaderElements.TOGGLE_LAYERS, this.#toggleLayers],
            [HeaderElements.TOGGLE_READABLE_REDACTIONS, this.#toggleReadableRedactions],
            [HeaderElements.LOAD_ALL_ANNOTATIONS, this.#loadAllAnnotations],
            [HeaderElements.COMPARE_BUTTON, this.#compare],
            [HeaderElements.CLOSE_COMPARE_BUTTON, this.#closeCompare],
        ]);
        this.toggleLoadAnnotations$ = this.#toggleLoadAnnotations$;

        this.updateElements();
    }

    enable(elements: HeaderElementType[]): void {
        this.#updateState(elements, true);
    }

    disable(elements: HeaderElementType[]): void {
        this.#updateState(elements, false);
    }

    updateElements(): void {
        this._pdf.instance?.UI.setHeaderItems(header => {
            const enabledItems: IHeaderElement[] = [];
            const groups: HeaderElementType[][] = [
                [HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON],
                [HeaderElements.TOGGLE_TOOLTIPS],
                [HeaderElements.TOGGLE_LAYERS],
                [HeaderElements.TOGGLE_READABLE_REDACTIONS],
                [HeaderElements.SHAPE_TOOL_GROUP_BUTTON],
                [
                    HeaderElements.ROTATE_LEFT_BUTTON,
                    HeaderElements.ROTATE_RIGHT_BUTTON,
                    HeaderElements.APPLY_ROTATION,
                    HeaderElements.DISCARD_ROTATION,
                ],
            ];

            const loadAllAnnotationsButton = this.#buttons.get(HeaderElements.LOAD_ALL_ANNOTATIONS);
            const startLoadAnnotations = 3;
            let startButtons = 10;
            let deleteCount = 14;

            groups.forEach(group => this.#pushGroup(enabledItems, group));

            if (!header.getItems().includes(loadAllAnnotationsButton)) {
                if (this.#isEnabled(HeaderElements.LOAD_ALL_ANNOTATIONS)) {
                    header.getItems().splice(startLoadAnnotations, 0, loadAllAnnotationsButton);
                    startButtons = 11;
                    deleteCount = 15;
                }
            } else if (!this.#isEnabled(HeaderElements.LOAD_ALL_ANNOTATIONS)) {
                header.getItems().splice(startLoadAnnotations, 1);
            }

            header.getItems().splice(startButtons, header.getItems().length - deleteCount, ...enabledItems);
        });

        this._pdf.instance?.UI.updateElement('selectToolButton', {
            img: this.#convertPath('/assets/icons/general/pdftron-cursor.svg'),
        });
    }

    disableLoadAllAnnotations(): void {
        this._pdf.instance.UI.updateElement(HeaderElements.LOAD_ALL_ANNOTATIONS, {
            img: this.#convertPath('/assets/icons/general/pdftron-action-load-all-annotations-disabled.svg'),
            onClick: undefined,
        });
    }

    enableLoadAllAnnotations(): void {
        this._pdf.instance.UI.updateElement(HeaderElements.LOAD_ALL_ANNOTATIONS, {
            img: this.#convertPath('/assets/icons/general/pdftron-action-load-all-annotations.svg'),
            onClick: () => this._ngZone.run(() => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS })),
        });
    }

    enableRotationButtons(): void {
        this.enable(ROTATION_BUTTONS);
    }

    disableRotationButtons(): void {
        this.disable(ROTATION_BUTTONS);
        this.#discardRotation();
    }

    resetCompareButtons() {
        this.disable([HeaderElements.CLOSE_COMPARE_BUTTON]);
        this.enable([HeaderElements.COMPARE_BUTTON]);
    }

    #closeCompareMode() {
        this._pdf.closeCompareMode();
        const { dossierId, fileId } = this._pdf;
        const file = this._filesMapService.get(dossierId, fileId);
        const filename = file.filename ?? 'document.pdf';

        this._pdf.instance.UI.loadDocument(this.#docBeforeCompare, { filename });

        this.resetCompareButtons();

        this._pdf.navigateTo(1);
    }

    #pushGroup(items: IHeaderElement[], group: HeaderElementType[]) {
        const enabledItems = group.filter(item => this.#isEnabled(item));
        if (enabledItems.length) {
            items.push(divider);
            enabledItems.forEach(item => items.push(this.#buttons.get(item)));
        }
    }

    #updateState(elements: HeaderElementType[], value: boolean) {
        if (this.#iqserPermissionService.has(Roles.getRss)) {
            elements = elements.filter(element => element !== HeaderElements.SHAPE_TOOL_GROUP_BUTTON);
        }
        if (this.#isDocumine) {
            elements = elements.filter(element => element !== HeaderElements.COMPARE_BUTTON);
        }
        elements.forEach(element => this.#config.set(element, value));
        this.updateElements();
    }

    #isEnabled(key: HeaderElementType): boolean {
        return this.#config.get(key);
    }

    #discardRotation(): void {
        this._rotationService.discardRotation();
        this.disable(ROTATION_ACTION_BUTTONS);
    }

    #toggleRotationActionButtons() {
        if (this._rotationService.hasRotations()) {
            this.enable(ROTATION_ACTION_BUTTONS);
        } else {
            this.disable(ROTATION_ACTION_BUTTONS);
        }
    }

    resetLayers() {
        this._layersService.resetLayers();
    }
}
