import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { IconButtonTypes, IqserDialogComponent, LoadingService, Toaster } from '@iqser/common-ui';
import { getCurrentUser } from '@iqser/common-ui/lib/users';
import { File, User, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { FilesService } from '@services/files/files.service';
import { PermissionsService } from '@services/permissions.service';
import { UserService } from '@users/user.service';
import { moveElementInArray } from '@utils/functions';

class DialogData {
    targetStatus: WorkflowFileStatus;
    files: File[];
    ignoreChanged?: boolean;
    withUnassignedOption?: boolean;
    withCurrentUserAsDefault?: boolean;
}

@Component({
    templateUrl: './assign-reviewer-approver-dialog.component.html',
})
export class AssignReviewerApproverDialogComponent extends IqserDialogComponent<
    AssignReviewerApproverDialogComponent,
    DialogData,
    boolean
> {
    readonly #dossier = this._activeDossiersService.find(this.data.files[0].dossierId);
    readonly #isApprover = this.permissionsService.isApprover(this.#dossier);
    readonly iconButtonTypes = IconButtonTypes;
    readonly currentUser = getCurrentUser<User>();
    readonly mode = this.#mode;
    readonly userOptions = this.#userOptions;
    readonly form = this.#form;

    constructor(
        readonly userService: UserService,
        private readonly _toaster: Toaster,
        private readonly _formBuilder: FormBuilder,
        private readonly _activeDossiersService: ActiveDossiersService,
        private readonly _filesService: FilesService,
        private readonly _loadingService: LoadingService,
        readonly permissionsService: PermissionsService,
    ) {
        super();
    }

    get selectedUser(): string {
        const value = this.form.controls.user.value;
        return value === 'undefined' ? undefined : value;
    }

    get changed(): boolean {
        if (this.data.ignoreChanged) {
            return true;
        }

        const selectedUser = this.selectedUser;
        for (const file of this.data.files) {
            if (file.assignee !== selectedUser) {
                return true;
            }
        }

        return false;
    }

    get validOption() {
        const currentUser = this.form.get('user').value;
        return !!this.userOptions.find(u => u === currentUser);
    }

    get #mode() {
        const isUnderApproval = this.data.targetStatus === WorkflowFileStatuses.UNDER_APPROVAL;
        const isApproved = this.data.targetStatus === WorkflowFileStatuses.APPROVED;
        return isUnderApproval || isApproved ? 'approver' : 'reviewer';
    }

    get #userOptions() {
        const unassignUser = this.#canUnassignUser && this.data.withUnassignedOption ? ['undefined'] : [];
        const cannotAssignUser = !this.permissionsService.canAssignUser(this.data.files, this.#dossier, this.data.targetStatus);
        if (cannotAssignUser) {
            return [...unassignUser];
        }

        if (this.mode === 'reviewer') {
            return this.#customSort([...this.#dossier.memberIds, ...unassignUser]);
        }

        return this.#customSort([...this.#dossier.approverIds, ...unassignUser]);
    }

    get #canUnassignUser() {
        return this.permissionsService.canUnassignUser(this.data.files, this.#dossier);
    }

    get #user() {
        if (this.data.files.every(file => !file.assignee)) {
            return null;
        }

        const files = this.data.files;
        const hasOnlyOneFile = this.hasOnlyOneFile(files);
        if (this.mode === 'reviewer') {
            if (!hasOnlyOneFile) {
                return this.currentUser.id;
            }

            if (files[0].assignee) {
                return files[0].assignee;
            }

            return this.data.withCurrentUserAsDefault ? this.currentUser.id : undefined;
        }

        const assignee = files[0].assignee;
        if (hasOnlyOneFile && this.permissionsService.isApprover(this.#dossier, assignee)) {
            const foundAssignee = this.userOptions.find(userOption => userOption === assignee);
            return foundAssignee ?? this.#userOptions[0];
        }

        return this.#isApprover ? this.currentUser.id : this.userOptions.at(0);
    }

    get #form() {
        const user = this.#user;
        return this._formBuilder.group({
            // Allow a null reviewer if a previous reviewer exists (= it's not the first assignment) & current user is allowed to unassign
            user: [user, this.#canUnassignUser && !user ? Validators.required : null],
        });
    }

    hasOnlyOneFile(files: File[]): files is [File] {
        return files.length === 1;
    }

    async save() {
        this._loadingService.start();
        const selectedUser = this.selectedUser;

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

        this._loadingService.stop();
        this.close(true);
    }

    #customSort(ids: string[]) {
        let sorted = ids.sort((a, b) => this.userService.getName(a).localeCompare(this.userService.getName(b)));

        if (this.mode === 'reviewer' || (this.mode === 'approver' && this.#isApprover)) {
            sorted = moveElementInArray(sorted, this.currentUser.id, 0);
        }

        if (sorted.includes('undefined')) {
            sorted = moveElementInArray(sorted, 'undefined', 1);
        }

        return sorted;
    }
}
