import { IqserPermissionsService } from '@iqser/common-ui';
import { Dictionary } from '@red/domain';
import { Roles } from '@users/roles';
import { isArray } from 'lodash-es';
import {
    canAcceptRecommendation,
    canChangeLegalBasis,
    canForceHint,
    canForceRedaction,
    canMarkAsFalsePositive,
    canRecategorizeAnnotation,
    canRemoveFromDictionary,
    canRemoveOnlyHere,
    canRemoveRedaction,
    canResizeAnnotation,
    canUndo,
} from './annotation-permissions.utils';
import { AnnotationWrapper } from './annotation.wrapper';
import { IMAGE_CATEGORIES } from '../../modules/file-preview/utils/constants';

export class AnnotationPermissions {
    canUndo = true;
    canAcceptRecommendation = true;
    canMarkAsFalsePositive = true;
    canRemoveOnlyHere = true;
    canRemoveFromDictionary = true;
    canRemoveRedaction = true;
    canForceRedaction = true;
    canChangeLegalBasis = true;
    canResizeAnnotation = true;
    canRecategorizeAnnotation = true;
    canForceHint = true;
    canEditAnnotations = true;
    canEditHints = true;
    canEditImages = true;

    static forUser(
        isApprover: boolean,
        annotations: AnnotationWrapper | AnnotationWrapper[],
        entities: Dictionary[],
        permissionsService: IqserPermissionsService,
    ) {
        if (!isArray(annotations)) {
            annotations = [annotations];
        }

        const summedPermissions: AnnotationPermissions = new AnnotationPermissions();
        const canAddRedaction = permissionsService.has(Roles.redactions.write);

        for (const annotation of annotations) {
            const permissions: AnnotationPermissions = new AnnotationPermissions();
            const annotationEntity = entities.find(entity => entity.type === annotation.type);
            permissions.canUndo = canUndo(annotation, isApprover);
            permissions.canForceHint = canForceHint(annotation, canAddRedaction);
            permissions.canForceRedaction = canForceRedaction(annotation, canAddRedaction);
            permissions.canAcceptRecommendation = canAcceptRecommendation(annotation);
            permissions.canMarkAsFalsePositive = canMarkAsFalsePositive(annotation, annotationEntity);
            permissions.canRemoveOnlyHere = canRemoveOnlyHere(annotation, canAddRedaction);
            permissions.canRemoveFromDictionary = canRemoveFromDictionary(annotation);
            permissions.canRemoveRedaction = canRemoveRedaction(annotation, permissions);
            permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
            permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
            permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction);

            permissions.canEditAnnotations = (annotation.isSkipped || annotation.isRedacted) && !annotation.isImage;
            permissions.canEditHints =
                annotation.isIgnoredHint || annotation.isDictBasedHint || annotation.isHint || annotation.isSuggestionForceHint;
            permissions.canEditImages = [...IMAGE_CATEGORIES, 'ocr'].includes(annotation.type);

            summedPermissions._merge(permissions);
        }
        return summedPermissions;
    }

    static reduce(permissions: AnnotationPermissions[]): AnnotationPermissions {
        const result = new AnnotationPermissions();
        result.canResizeAnnotation = permissions.length === 1 && permissions[0].canResizeAnnotation;
        result.canChangeLegalBasis = permissions.reduce((acc, next) => acc && next.canChangeLegalBasis, true);
        result.canRecategorizeAnnotation = permissions.reduce((acc, next) => acc && next.canRecategorizeAnnotation, true);
        result.canRemoveFromDictionary = permissions.reduce((acc, next) => acc && next.canRemoveFromDictionary, true);
        result.canAcceptRecommendation = permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true);
        result.canMarkAsFalsePositive = permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true);
        result.canForceRedaction = permissions.reduce((acc, next) => acc && next.canForceRedaction, true);
        result.canForceHint = permissions.reduce((acc, next) => acc && next.canForceHint, true);
        result.canRemoveOnlyHere = permissions.reduce((acc, next) => acc && next.canRemoveOnlyHere, true);
        result.canRemoveRedaction = permissions.reduce((acc, next) => acc && next.canRemoveRedaction, true);
        result.canUndo = permissions.reduce((acc, next) => acc && next.canUndo, true);
        result.canEditAnnotations = permissions.reduce((acc, next) => acc && next.canEditAnnotations, true);
        result.canEditHints = permissions.reduce((acc, next) => acc && next.canEditHints, true);
        result.canEditImages = permissions.reduce((acc, next) => acc && next.canEditImages, true);
        return result;
    }

    private _merge(permissions: AnnotationPermissions) {
        for (const key of Object.keys(this)) {
            if (typeof this[key] === 'boolean') {
                this[key] = this[key] && permissions[key];
            }
        }
    }
}
