import { computed, Injectable, Injector, Signal, signal } from '@angular/core';
import { firstValueFrom, Observable, of } from 'rxjs';
import { RotationType } from '@red/domain';
import { FileManagementService } from '@services/files/file-management.service';
import { map, tap } from 'rxjs/operators';
import {
    ConfirmationDialogComponent,
    ConfirmOption,
    ConfirmOptions,
    defaultDialogConfig,
    IConfirmationDialogData,
    LoadingService,
} from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { MatDialog } from '@angular/material/dialog';
import { FilesService } from '@services/files/files.service';
import { PdfViewer } from './pdf-viewer.service';
import { FilesMapService } from '@services/files/files-map.service';
import { NGXLogger } from 'ngx-logger';
import { REDDocumentViewer } from './document-viewer.service';
import { toObservable } from '@angular/core/rxjs-interop';

@Injectable()
export class PageRotationService {
    readonly rotations$: Observable<Record<number, number>>;
    readonly rotations: Signal<Record<number, number>>;
    readonly hasRotations: Signal<boolean>;
    readonly #rotations = signal<Record<number, number>>({});

    constructor(
        private readonly _pdf: PdfViewer,
        private readonly _loadingService: LoadingService,
        private readonly _logger: NGXLogger,
        private readonly _injector: Injector,
        private readonly _fileManagementService: FileManagementService,
        private readonly _filesService: FilesService,
        private readonly _filesMapService: FilesMapService,
        private readonly _documentViewer: REDDocumentViewer,
    ) {
        this.rotations$ = toObservable(this.#rotations);
        this.rotations = this.#rotations.asReadonly();
        this.hasRotations = computed(() => Object.values(this.#rotations()).filter(v => !!v).length > 0);
    }

    get currentPageRotation() {
        const savedRotation = this._documentViewer.currentPageRotation;
        const currentRotation = this.#rotations()[this._pdf.currentPage()] ?? 0;
        const rotationsSum = savedRotation + currentRotation;
        return Math.abs(rotationsSum < 360 ? rotationsSum : 360 - rotationsSum);
    }

    async applyRotation() {
        this._loadingService.start();
        const pages = this.#rotations();
        const { dossierId, fileId } = this._pdf;

        if (!dossierId || !fileId) {
            this._loadingService.stop();
            return this._logger.error('No dossier id or file id while applying rotations: ', dossierId, fileId);
        }

        const file = this._filesMapService.get(dossierId, fileId);
        if (!file) {
            this._loadingService.stop();
            return this._logger.error('Cannot find file: ', dossierId, fileId);
        }

        const request$ = this._fileManagementService.rotatePage({ pages }, dossierId, fileId);
        this.clearRotations();
        await firstValueFrom(request$);
        await this._filesService.reload(dossierId, file);

        this._loadingService.stop();
    }

    discardRotation() {
        this._documentViewer.resetRotation(Object.keys(this.#rotations()));
        this.clearRotations();
    }

    addRotation(rotation: RotationType): void {
        const pageNumber = this._pdf.currentPage();
        const pageRotation = this.#rotations()[pageNumber];
        const rotationValue = pageRotation ? (pageRotation + Number(rotation)) % 360 : rotation;

        this.#rotations.update(value => ({ ...value, [pageNumber]: rotationValue }));
        this._documentViewer.rotate(rotation);
    }

    clearRotations() {
        this.#rotations.set({});
    }

    showConfirmationDialogIfHasRotations() {
        return this.hasRotations() ? this.#showConfirmationDialog() : of(false);
    }

    #showConfirmationDialog() {
        const ref = this._injector.get(MatDialog).open(ConfirmationDialogComponent, {
            ...defaultDialogConfig,
            data: {
                title: _('page-rotation.confirmation-dialog.title'),
                question: _('page-rotation.confirmation-dialog.question'),
                confirmationText: _('page-rotation.apply'),
                discardChangesText: _('page-rotation.discard'),
            } as IConfirmationDialogData,
        });

        const closed$ = ref.afterClosed().pipe(map((option: ConfirmOption) => option === ConfirmOptions.CONFIRM));

        return closed$.pipe(tap(apply => (apply ? this.applyRotation() : this.discardRotation())));
    }
}
