import { Component, Inject, OnInit } from '@angular/core';
import { Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { BaseDialogComponent, IqserPermissionsService } from '@iqser/common-ui';
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
import { Dictionary, Dossier, File, IAddRedactionRequest, SuperTypes } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { JustificationsService } from '@services/entity-services/justifications.service';
import { Roles } from '@users/roles';
import { firstValueFrom } from 'rxjs';
import { ManualRedactionService } from '../../services/manual-redaction.service';

export interface LegalBasisOption {
    label?: string;
    legalBasis?: string;
    description?: string;
}

@Component({
    templateUrl: './manual-annotation-dialog.component.html',
    styleUrls: ['./manual-annotation-dialog.component.scss'],
})
export class ManualAnnotationDialogComponent extends BaseDialogComponent implements OnInit {
    readonly #dossier: Dossier;
    readonly roles = Roles;
    isDictionaryRequest: boolean;
    isFalsePositiveRequest: boolean;
    isEditingSelectedText = false;
    applyOnMultiplePages = false;
    manualRedactionTypeExists = true;
    possibleDictionaries: Dictionary[] = [];
    legalOptions: LegalBasisOption[] = [];

    constructor(
        readonly iqserPermissionsService: IqserPermissionsService,
        private readonly _justificationsService: JustificationsService,
        private readonly _manualRedactionService: ManualRedactionService,
        activeDossiersService: ActiveDossiersService,
        private readonly _dictionaryService: DictionaryService,
        protected readonly _dialogRef: MatDialogRef<ManualAnnotationDialogComponent>,
        @Inject(MAT_DIALOG_DATA) readonly data: { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string; file: File },
    ) {
        super(_dialogRef);
        this.#dossier = activeDossiersService.find(this.data.dossierId);

        this.isFalsePositiveRequest = this.data.manualRedactionEntryWrapper.type === 'FALSE_POSITIVE';
        this.isDictionaryRequest = this.data.manualRedactionEntryWrapper.type === 'DICTIONARY' || this.isFalsePositiveRequest;

        this.manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId);

        this.form = this.#getForm();
        this.initialFormValue = this.form.getRawValue();
    }

    get title() {
        return this._manualRedactionService.getTitle(this.data.manualRedactionEntryWrapper.type);
    }

    get isRectangle() {
        return !!this.data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle;
    }

    get displayedDictionaryLabel() {
        const dictType = this.form.get('dictionary').value;
        if (dictType) {
            return this.possibleDictionaries.find(d => d.type === dictType).label;
        }
        return null;
    }

    get disabled() {
        return this.form.invalid || (this.applyOnMultiplePages && !this.form.get('multiplePages')?.value);
    }

    async ngOnInit() {
        this.possibleDictionaries = this.isDictionaryRequest
            ? await this._dictionaryService.getDictionariesOptions(this.#dossier.dossierTemplateId, this.#dossier.id)
            : this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId);

        const data = await firstValueFrom(this._justificationsService.getForDossierTemplate(this.#dossier.dossierTemplateId));
        this.legalOptions = data.map(lbm => ({
            legalBasis: lbm.reason,
            description: lbm.description,
            label: lbm.name,
        }));

        this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));

        this.#selectReason();

        if (!this.isRectangle) {
            this.#formatSelectedTextValue();
        }
    }

    save() {
        this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
        try {
            const annotations =
                this.isRectangle && !!this.form.get('multiplePages').value
                    ? this.#getRectangles()
                    : [this.data.manualRedactionEntryWrapper];
            this._dialogRef.close({
                annotations,
                dictionary: this.possibleDictionaries.find(d => d.type === this.form.get('dictionary').value),
            });
        } catch (e) {
            this._toaster.error(_('manual-annotation.dialog.error'));
        }
    }

    #getRectangles() {
        const quads = this.data.manualRedactionEntryWrapper.manualRedactionEntry.positions.find(a => !!a);
        const value: string = this.form.get('multiplePages').value.replace(/[^0-9-,]/g, '');
        const entry = { ...this.data.manualRedactionEntryWrapper.manualRedactionEntry };
        const wrapper = { ...this.data.manualRedactionEntryWrapper };
        const wrappers: ManualRedactionEntryWrapper[] = [wrapper];

        value.split(',').forEach(range => {
            const splitted = range.split('-');
            const startPage = parseInt(splitted[0], 10);
            const endPage = splitted.length > 1 ? parseInt(splitted[1], 10) : startPage;
            if (!startPage || !endPage || startPage > this.data.file.numberOfPages || endPage > this.data.file.numberOfPages) {
                throw new Error();
            }

            for (let page = startPage; page <= endPage; page++) {
                if (page === wrapper.manualRedactionEntry.positions[0].page) {
                    continue;
                }
                const manualRedactionEntry = { ...entry, positions: [{ ...quads, page }] };
                wrappers.push({ ...wrapper, manualRedactionEntry });
            }
        });

        return wrappers;
    }

    #formatSelectedTextValue() {
        this.data.manualRedactionEntryWrapper.manualRedactionEntry.value =
            this.data.manualRedactionEntryWrapper.manualRedactionEntry.value.replace(
                // eslint-disable-next-line no-control-regex,max-len
                /([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi,
                '$1',
            );
    }

    #getForm() {
        return this._formBuilder.group({
            selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value,
            section: [null],
            reason: this.isDictionaryRequest ? [null] : [null, Validators.required],
            dictionary: this.isDictionaryRequest
                ? [this.isFalsePositiveRequest ? 'false_positive' : null, Validators.required]
                : [this.manualRedactionTypeExists ? SuperTypes.ManualRedaction : null, Validators.required],
            comment: [null],
            classification: ['non-readable content'],
            multiplePages: '',
        });
    }

    #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
        const legalOption: LegalBasisOption = this.form.get('reason').value;
        addRedactionRequest.type = this.form.get('dictionary').value;
        if (legalOption) {
            addRedactionRequest.reason = legalOption.description;
            addRedactionRequest.legalBasis = legalOption.legalBasis;
        }

        if (this.iqserPermissionsService.has(Roles.getRss)) {
            const selectedType = this.possibleDictionaries.find(d => d.type === addRedactionRequest.type);
            addRedactionRequest.addToDictionary = selectedType.hasDictionary;
        } else {
            addRedactionRequest.addToDictionary = this.isDictionaryRequest && addRedactionRequest.type !== 'dossier_redaction';
        }

        if (!addRedactionRequest.reason) {
            addRedactionRequest.reason = 'Dictionary Request';
        }
        const commentValue = this.form.get('comment').value;
        addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
        addRedactionRequest.section = this.form.get('section').value;
        addRedactionRequest.value = addRedactionRequest.rectangle
            ? this.form.get('classification').value
            : this.form.get('selectedText').value;
    }

    #selectReason() {
        if (this.legalOptions.length === 1) {
            this.form.get('reason').setValue(this.legalOptions[0]);
        }
    }
}
