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

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 _iqserDialog: IqserDialog,
        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);
    }

    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);
        let userId: string;

        if (file.isNew) {
            userId = currentUserId;
        }

        if (
            file.assignee === currentUserId ||
            (!file.assignee &&
                targetStatus === WorkflowFileStatuses.UNDER_REVIEW &&
                file.workflowStatus === WorkflowFileStatuses.UNDER_APPROVAL)
        ) {
            if (eligibleUsersIds.includes(currentUserId)) {
                userId = currentUserId;
            }
        } else if (eligibleUsersIds.length === 1) {
            userId = eligibleUsersIds[0];
        }

        if (userId) {
            return this.#makeAssignFileRequest(userId, targetStatus, [file]);
        }

        this._iqserDialog.openDefault(AssignReviewerApproverDialogComponent, {
            data: {
                targetStatus,
                files: [file],
                ignoreChanged,
                withCurrentUserAsDefault: file.assignee !== currentUserId,
            },
        });
    }

    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();
    }

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