import { AsyncPipe, NgClass, NgForOf, NgIf, NgStyle } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatDialogClose } from '@angular/material/dialog';
import { MatFormField } from '@angular/material/form-field';
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
import { MatTooltip } from '@angular/material/tooltip';
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
import { CircleButtonComponent, HasScrollbarDirective, IconButtonComponent, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core';
import { Dictionary, 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 { UserPreferenceService } from '@users/user-preference.service';
import { calcTextWidthInPixels, stringToBoolean } from '@utils/functions';
import { firstValueFrom, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults';
import { getRedactOrHintOptions } from '../../utils/dialog-options';
import { RedactOrHintOption, RedactOrHintOptions, RedactTextData, RedactTextResult } from '../../utils/dialog-types';
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';

const MAXIMUM_TEXT_AREA_WIDTH = 421;

@Component({
    templateUrl: './redact-text-dialog.component.html',
    styleUrls: ['./redact-text-dialog.component.scss'],
    standalone: true,
    imports: [
        ReactiveFormsModule,
        NgClass,
        NgIf,
        NgStyle,
        HasScrollbarDirective,
        CircleButtonComponent,
        DetailsRadioComponent,
        MatFormField,
        MatSelectTrigger,
        MatSelect,
        MatOption,
        NgForOf,
        MatTooltip,
        TranslateModule,
        AsyncPipe,
        IconButtonComponent,
        MatDialogClose,
    ],
})
export class RedactTextDialogComponent
    extends IqserDialogComponent<RedactTextDialogComponent, RedactTextData, RedactTextResult>
    implements OnInit
{
    readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId);
    readonly #manualRedactionTypeExists = inject(DictionaryService).hasManualType(this.#dossier.dossierTemplateId);
    #applyToAllDossiers = this.applyToAll;
    readonly roles = Roles;
    readonly iconButtonTypes = IconButtonTypes;
    readonly initialText = this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value;
    readonly form: FormGroup;
    dictionaryRequest = false;
    legalOptions: LegalBasisOption[] = [];
    dictionaries: Dictionary[] = [];
    isEditingSelectedText = false;
    modifiedText = this.initialText;
    selectedTextRows = 1;
    readonly options: DetailsRadioOption<RedactOrHintOption>[];
    readonly displayedDictionaryLabel$: Observable<string>;
    readonly maximumTextAreaWidth = MAXIMUM_TEXT_AREA_WIDTH;
    readonly maximumSelectedTextWidth = 567;

    textWidth: number;

    constructor(
        private readonly _justificationsService: JustificationsService,
        private readonly _dictionaryService: DictionaryService,
        private readonly _formBuilder: FormBuilder,
        private readonly _userPreferences: UserPreferenceService,
    ) {
        super();
        this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover, this.data.isPageExcluded);
        this.form = this.#getForm();
        this.#setupValidators(this.dictionaryRequest ? RedactOrHintOptions.IN_DOSSIER : RedactOrHintOptions.ONLY_HERE);
        this.textWidth = calcTextWidthInPixels(this.form.controls.selectedText.value);
        this.form.controls.option.valueChanges
            .pipe(
                tap((option: DetailsRadioOption<RedactOrHintOption>) => {
                    this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER;
                    if (this.dictionaryRequest) {
                        this.#setDictionaries();
                        this.form.patchValue({ selectedText: this.modifiedText });
                    } else {
                        this.isEditingSelectedText = false;
                        this.modifiedText = this.form.controls.selectedText.value;
                        this.form.patchValue({ selectedText: this.initialText }, { emitEvent: true });
                    }
                    this.#setupValidators(option.value);
                    this.#resetValues();
                }),
                takeUntilDestroyed(),
            )
            .subscribe();

        this.displayedDictionaryLabel$ = this.form.controls.dictionary.valueChanges.pipe(
            map(dictionary => this.dictionaries.find(d => d.type === dictionary)?.label ?? null),
        );
    }

    get isSystemDefault(): boolean {
        return this._userPreferences.getAddRedactionDefaultOption() === SystemDefaultOption.SYSTEM_DEFAULT;
    }

    get defaultOption() {
        const defaultOption = this.isSystemDefault
            ? this.#getOption(SystemDefaults.ADD_REDACTION_DEFAULT)
            : this.#getOption(this._userPreferences.getAddRedactionDefaultOption() as RedactOrHintOption);
        this.dictionaryRequest = defaultOption.value === RedactOrHintOptions.IN_DOSSIER;
        if (this.dictionaryRequest) {
            this.#setDictionaries();
            return defaultOption;
        }
        return defaultOption ?? this.options[0];
    }

    get applyToAll() {
        return this.isSystemDefault || this._userPreferences.getAddRedactionDefaultExtraOption() === 'undefined'
            ? this.data.applyToAllDossiers ?? true
            : stringToBoolean(this._userPreferences.getAddRedactionDefaultExtraOption());
    }

    async ngOnInit(): Promise<void> {
        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();
        this.#resetValues();
    }

    undoTextChange() {
        this.form.patchValue({ selectedText: this.initialText });
    }

    extraOptionChanged(option: DetailsRadioOption<RedactOrHintOption>): void {
        this.#applyToAllDossiers = option.extraOption.checked;

        this.#setDictionaries();
        if (this.#applyToAllDossiers && this.form.controls.dictionary.value) {
            const selectedDictionaryLabel = this.form.controls.dictionary.value;
            const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryLabel);
            if (!selectedDictionary) {
                this.form.controls.dictionary.setValue(null);
            }
        }
    }

    typeChanged() {
        if (!this.#applyToAllDossiers) {
            const selectedDictionaryType = this.form.controls.dictionary.value;
            const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryType);
            this.options[1].extraOption.disabled = selectedDictionary.dossierDictionaryOnly;
        }
    }

    save(): void {
        this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
        const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry;
        this.close({
            redaction,
            dictionary: this.dictionaries.find(d => d.type === this.form.controls.dictionary.value),
        });
    }

    toggleEditingSelectedText() {
        this.isEditingSelectedText = !this.isEditingSelectedText;
        if (this.isEditingSelectedText) {
            const width = calcTextWidthInPixels(this.form.controls.selectedText.value);
            this.selectedTextRows = Math.ceil(width / MAXIMUM_TEXT_AREA_WIDTH);
        }
    }

    #setupValidators(option: RedactOrHintOption) {
        switch (option) {
            case RedactOrHintOptions.IN_DOSSIER:
                this.form.controls.reason.clearValidators();
                this.form.controls.dictionary.addValidators(Validators.required);
                break;
            case RedactOrHintOptions.ONLY_HERE:
                this.form.controls.dictionary.clearValidators();
                this.form.controls.reason.addValidators(Validators.required);
                break;
        }

        this.form.controls.reason.updateValueAndValidity();
        this.form.controls.dictionary.updateValueAndValidity();
    }

    #setDictionaries() {
        this.dictionaries = this._dictionaryService.getRedactTextDictionaries(this.#dossier.dossierId, !this.#applyToAllDossiers);
    }

    #getForm(): FormGroup {
        return this._formBuilder.group({
            selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value,
            reason: [null as LegalBasisOption],
            comment: [null],
            dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null],
            option: this.defaultOption,
        });
    }

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

    #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
        addRedactionRequest.type = this.form.controls.dictionary.value;
        addRedactionRequest.section = null;
        addRedactionRequest.value = this.form.controls.selectedText.value;

        const legalOption: LegalBasisOption = this.form.controls.reason.value;
        if (legalOption) {
            addRedactionRequest.reason = legalOption.description;
            addRedactionRequest.legalBasis = legalOption.legalBasis;
        }

        const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type);

        if (selectedType) {
            addRedactionRequest.addToDictionary = selectedType.hasDictionary;
        } else {
            addRedactionRequest.addToDictionary = this.dictionaryRequest && addRedactionRequest.type !== 'dossier_redaction';
        }

        if (!addRedactionRequest.reason) {
            addRedactionRequest.reason = 'Dictionary Request';
        }
        const commentValue = this.form.controls.comment.value;
        addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
        addRedactionRequest.addToAllDossiers = this.data.isApprover && this.dictionaryRequest && this.#applyToAllDossiers;
    }

    #resetValues() {
        this.#applyToAllDossiers = this.applyToAll;
        this.options[1].extraOption.checked = this.#applyToAllDossiers;
        if (this.dictionaryRequest) {
            this.form.controls.reason.setValue(null);
            this.form.controls.dictionary.setValue(null);
            return;
        }
        this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
    }

    #getOption(option: RedactOrHintOption): DetailsRadioOption<RedactOrHintOption> {
        return this.options.find(o => o.value === option);
    }
}
