import { Injectable } from '@angular/core';
import { Dossier, File, User, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { DossiersDialogService } from './dossiers-dialog.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesService } from '@services/files/files.service';
import { IConfirmationDialogData, LoadingService, Toaster } from '@iqser/common-ui';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { firstValueFrom } from 'rxjs';
import { getCurrentUser } from '@iqser/common-ui/lib/users';

const atLeastOneAssignee = (files: File[]) => files.reduce((acc, fs) => acc || !!fs.assignee, false);

@Injectable()
export class FileAssignService {
    readonly currentUser = getCurrentUser<User>();

    constructor(
        private readonly _toaster: Toaster,
        private readonly _filesService: FilesService,
        private readonly _loadingService: LoadingService,
        private readonly _dialogService: DossiersDialogService,
        private readonly _activeDossiersService: ActiveDossiersService,
    ) {}

    async assignToMe(files: File[]): Promise<unknown> {
        const assignReq = async () => {
            this._loadingService.start();
            if (files[0].isNew) {
                await this._makeAssignFileRequest(this.currentUser.id, 'UNDER_REVIEW', files);
            } else {
                await this._filesService.setAssignee(files, this.currentUser.id);
            }
            this._loadingService.stop();
        };

        if (atLeastOneAssignee(files)) {
            const dialogInput: IConfirmationDialogData = {
                title: _('confirmation-dialog.assign-file-to-me.title'),
                question:
                    files.length === 1
                        ? _('confirmation-dialog.assign-file-to-me.question.single')
                        : _('confirmation-dialog.assign-file-to-me.question.multiple'),
            };
            const ref = this._dialogService.openDialog('confirm', dialogInput, assignReq);
            return firstValueFrom(ref.afterClosed());
        }

        return assignReq();
    }

    async assignReviewer(file: File, ignoreChanged = false): Promise<void> {
        await this._assignFile(WorkflowFileStatuses.UNDER_REVIEW, file, ignoreChanged);
    }

    async assignApprover(file: File, ignoreChanged = false): Promise<void> {
        await this._assignFile(WorkflowFileStatuses.UNDER_APPROVAL, file, ignoreChanged);
    }

    private async _assignFile(targetStatus: WorkflowFileStatus, file: File, ignoreChanged = false): Promise<void> {
        const currentUserId = this.currentUser.id;
        const currentDossier = this._activeDossiersService.find(file.dossierId);
        const eligibleUsersIds = this._getUserIds(targetStatus, currentDossier);

        if (file.isNew) {
            await this._makeAssignFileRequest(currentUserId, targetStatus, [file]);
        } else if (file.assignee === currentUserId) {
            if (eligibleUsersIds.includes(currentUserId)) {
                await this._makeAssignFileRequest(currentUserId, targetStatus, [file]);
            } else if (eligibleUsersIds.length === 1) {
                await this._makeAssignFileRequest(eligibleUsersIds[0], targetStatus, [file]);
            } else {
                const data = { targetStatus, files: [file], ignoreChanged };
                this._dialogService.openDialog('assignFile', data);
            }
        } else {
            if (eligibleUsersIds.length === 1) {
                await this._makeAssignFileRequest(eligibleUsersIds[0], targetStatus, [file]);
            } else {
                const data = { targetStatus, files: [file], ignoreChanged, withCurrentUserAsDefault: true };
                this._dialogService.openDialog('assignFile', data);
            }
        }
    }

    private async _makeAssignFileRequest(userId: string, targetStatus: WorkflowFileStatus, files: File[]) {
        this._loadingService.start();

        try {
            if (!userId || targetStatus === WorkflowFileStatuses.APPROVED) {
                await this._filesService.setAssignee(files, userId);
            } else if (targetStatus === WorkflowFileStatuses.UNDER_REVIEW) {
                await this._filesService.setReviewer(files, userId);
            } else {
                await this._filesService.setUnderApproval(files, userId);
            }
        } catch (error) {
            this._toaster.error(_('error.http.generic'), { params: error });
        }

        this._loadingService.stop();
    }

    private _getUserIds(targetStatus: WorkflowFileStatus, dossier: Dossier) {
        return targetStatus === WorkflowFileStatuses.UNDER_APPROVAL || targetStatus === WorkflowFileStatuses.APPROVED
            ? dossier.approverIds
            : dossier.memberIds;
    }
}
