import { NgForOf, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, input, OnInit, signal, untracked } from '@angular/core';
import { FormGroup, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
import { MatCheckbox } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef } from '@angular/material/dialog';
import { MatFormField, MatSuffix } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
import { MatTooltip } from '@angular/material/tooltip';
import { Router } from '@angular/router';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { SmallChipComponent } from '@common-ui/shared';
import {
    ConfirmOptions,
    HasScrollbarDirective,
    IconButtonComponent,
    IconButtonTypes,
    IConfirmationDialogData,
    LoadingService,
    TitleColors,
    Toaster,
} from '@iqser/common-ui';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { Dossier, DOSSIER_TEMPLATE_ID, IDossierRequest, IDossierTemplate } from '@red/domain';
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service';
import { DossierStatsService } from '@services/dossiers/dossier-stats.service';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service';
import { TrashService } from '@services/entity-services/trash.service';
import { PermissionsService } from '@services/permissions.service';
import { dateWithoutTime, formControlToSignal } from '@utils/functions';
import dayjs from 'dayjs';
import { firstValueFrom } from 'rxjs';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { type EditDossierDialogComponent } from '../edit-dossier-dialog.component';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { AsControl, isJustOne } from '@common-ui/utils';
import { DossierStatesService } from '@services/entity-services/dossier-states.service';

interface GeneralInfoForm {
    dossierName: string;
    dossierTemplateId: string;
    dossierStatusId?: string;
    description?: string;
    dueDate?: string;
}

@Component({
    selector: 'redaction-edit-dossier-general-info',
    templateUrl: './edit-dossier-general-info.component.html',
    styleUrls: ['./edit-dossier-general-info.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
    standalone: true,
    imports: [
        ReactiveFormsModule,
        MatFormField,
        TranslateModule,
        MatSelect,
        MatOption,
        NgForOf,
        MatTooltip,
        HasScrollbarDirective,
        SmallChipComponent,
        MatCheckbox,
        MatDatepickerModule,
        MatIcon,
        MatSuffix,
        IconButtonComponent,
        NgIf,
        MatSelectTrigger,
    ],
})
export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSectionInterface {
    readonly iconButtonTypes = IconButtonTypes;
    readonly dossier = input<Dossier>();
    hasDueDate: boolean;
    dossierTemplates: IDossierTemplate[];
    form: FormGroup<AsControl<GeneralInfoForm>> = this._formBuilder.group({
        dossierName: [null, Validators.required],
        dossierTemplateId: [null, Validators.required],
        dossierStatusId: [null],
        description: [null],
        dueDate: [null],
    });
    initialFormValue: GeneralInfoForm;
    readonly dossierStatusIdControl = formControlToSignal(this.form.controls.dossierStatusId);
    readonly dossierTemplateIdControl = formControlToSignal<GeneralInfoForm['dossierTemplateId']>(this.form.controls.dossierTemplateId);
    readonly states = signal([null]);
    readonly stateNameAndColor = computed(() => {
        const nameAndColor = {};
        this.states().forEach(stateId => {
            nameAndColor[stateId] = {
                name: this.#getStateName(stateId, untracked(this.dossierTemplateIdControl)),
                color: this.#getStateColor(stateId, untracked(this.dossierTemplateIdControl)),
            };
        });
        return nameAndColor;
    });
    readonly statePlaceholder = computed(() => this.#statePlaceholder);

    constructor(
        readonly permissionsService: PermissionsService,
        private readonly _dossierStatesMapService: DossierStatesMapService,
        private readonly _dossierTemplatesService: DossierTemplatesService,
        private readonly _dossiersService: DossiersService,
        private readonly _trashService: TrashService,
        private readonly _dossierStatsService: DossierStatsService,
        private readonly _formBuilder: UntypedFormBuilder,
        private readonly _dialogService: DossiersDialogService,
        private readonly _router: Router,
        private readonly _editDossierDialogRef: MatDialogRef<EditDossierDialogComponent>,
        private readonly _toaster: Toaster,
        private readonly _loadingService: LoadingService,
        private readonly _translateService: TranslateService,
        private readonly _archivedDossiersService: ArchivedDossiersService,
        private readonly _changeDetectorRef: ChangeDetectorRef,
        private readonly _dossierStatesService: DossierStatesService,
    ) {
        effect(() => {
            const shouldBeDisabled = this.#formValue.find(item => item.key === 'dossierTemplateId')?.disabled;
            if (
                (this.dossierStatusIdControl() !== this.initialFormValue.dossierStatusId && this.dossierStatusIdControl()) ||
                shouldBeDisabled
            ) {
                this.form.controls.dossierTemplateId.disable();
            } else {
                this.form.controls.dossierTemplateId.enable();
            }
        });

        effect(
            () => {
                this.states.set(this.#statesForDossierTemplate);
                this.#onDossierTemplateChange();
            },
            { allowSignalWrites: true },
        );
    }

    get changed(): boolean {
        for (const key of Object.keys(this.form.getRawValue())) {
            if (key === 'dueDate') {
                if (this.hasDueDate !== !!this.dossier().dueDate) {
                    return true;
                }
                if (this.hasDueDate && !dayjs(this.dossier().dueDate).isSame(dayjs(this.form.get(key).value), 'day')) {
                    return true;
                }
            } else if (this.dossier()[key] !== this.form.get(key).value) {
                return true;
            }
        }

        return false;
    }

    get valid(): boolean {
        return this.form.valid;
    }

    get disabled(): boolean {
        return this.hasDueDate && this.form.get('dueDate').value === null;
    }

    get #statePlaceholder(): string {
        return this._translateService.instant(
            isJustOne(this.states())
                ? 'edit-dossier-dialog.general-info.form.dossier-state.no-state-placeholder'
                : 'dossier-state.placeholder',
        ) as string;
    }

    get #statesForDossierTemplate() {
        return [
            null,
            ...this._dossierStatesMapService
                .get(this.dossierTemplateIdControl() ?? untracked(this.dossier).dossierTemplateId)
                .map(s => s.id),
        ];
    }

    get #formValue(): { key: string; value: string; disabled: boolean }[] {
        const dossier = untracked(this.dossier);
        const formFieldWithArchivedCheck = value => ({ value, disabled: !dossier.isActive });
        const states = untracked(this.states);
        return [
            {
                key: 'dossierName',
                ...formFieldWithArchivedCheck(dossier.dossierName),
            },
            {
                key: 'dossierTemplateId',
                value: dossier.dossierTemplateId,
                disabled: this._dossierStatsService.get(dossier.id).hasFiles || !dossier.isActive,
            },
            {
                key: 'dossierStatusId',
                value: dossier.dossierStatusId,
                disabled: isJustOne(states) || !dossier.isActive,
            },
            {
                key: 'description',
                ...formFieldWithArchivedCheck(dossier.description),
            },
            {
                key: 'dueDate',
                ...formFieldWithArchivedCheck(dossier.dueDate),
            },
        ];
    }

    ngOnInit() {
        if (isJustOne(this._dossierTemplatesService.all)) {
            this._loadingService.loadWhile(
                firstValueFrom(this._dossierTemplatesService.loadOnlyDossierTemplates()).then(async () => {
                    await firstValueFrom(this._dossierStatesService.loadAllForAllTemplates());
                    this.#filterInvalidDossierTemplates();
                }),
            );
        } else {
            this.#filterInvalidDossierTemplates();
        }
        this.#patchFormValue();
        if (!this.permissionsService.canEditDossier(this.dossier())) {
            this.form.disable();
        }
        this.hasDueDate = !!this.dossier().dueDate;
    }

    revert() {
        this.form.reset({
            dossierName: this.dossier().dossierName,
            dossierTemplateId: this.dossier().dossierTemplateId,
            dossierStatusId: this.dossier().dossierStatusId,
            description: this.dossier().description,
            dueDate: this.dossier().dueDate,
        });
        this.hasDueDate = !!this.dossier().dueDate;
        this.initialFormValue = this.form.getRawValue();
    }

    async save(): EditDossierSaveResult {
        const dueDate = dateWithoutTime(dayjs(this.form.get('dueDate').value));
        const dossier = {
            ...this.dossier(),
            dossierName: this.form.get('dossierName').value,
            description: this.form.get('description').value,
            dueDate: dueDate.isValid() ? dueDate.toISOString() : undefined,
            dossierTemplateId: this.form.get(DOSSIER_TEMPLATE_ID).value,
            dossierStatusId: this.form.get('dossierStatusId').value,
        } as IDossierRequest;

        const updatedDossier = await firstValueFrom(this._dossiersService.createOrUpdate(dossier));
        if (updatedDossier && updatedDossier.dossierTemplateId !== this.dossier().dossierTemplateId) {
            await this._router.navigate([updatedDossier.routerLink]);
        }
        this.initialFormValue = this.form.getRawValue();
        return { success: !!updatedDossier };
    }

    deleteDossier() {
        const data: IConfirmationDialogData = {
            title: _('confirmation-dialog.delete-dossier.title'),
            titleColor: TitleColors.WARN,
            question: _('confirmation-dialog.delete-dossier.question'),
            confirmationText: _('confirmation-dialog.delete-dossier.confirmation-text'),
            requireInput: true,
            denyText: _('confirmation-dialog.delete-dossier.deny-text'),
            translateParams: {
                dossierName: this.dossier().dossierName,
                dossiersCount: 1,
            },
        };

        this._dialogService.openDialog('confirm', data, async () => {
            this._loadingService.start();
            const successful = await this._trashService.deleteDossier(this.dossier());
            if (successful) {
                await this.#closeDialogAndRedirectToDossier();
            }
            this._loadingService.stop();
        });
    }

    archiveDossier() {
        const data: IConfirmationDialogData = {
            title: _('confirm-archive-dossier.title'),
            details: _('confirm-archive-dossier.details'),
            question: _('confirm-archive-dossier.warning'),
            confirmationText: _('confirm-archive-dossier.archive'),
            denyText: _('confirm-archive-dossier.cancel'),
            titleColor: TitleColors.WARN,
            translateParams: { ...this.dossier() },
            checkboxes: [{ value: false, label: _('confirm-archive-dossier.checkbox.documents') }],
            toastMessage: _('confirm-archive-dossier.toast-error'),
        };

        this._dialogService.openDialog('confirm', data, async result => {
            if (result === ConfirmOptions.CONFIRM) {
                this._loadingService.start();
                await firstValueFrom(this._archivedDossiersService.archive([this.dossier()]));
                this._toaster.success(_('dossier-listing.archive.archive-succeeded'), {
                    params: {
                        dossierName: this.dossier().dossierName,
                    },
                });
                this._editDossierDialogRef.close();
                this._loadingService.stop();
            }
        });
    }

    toggleDueDateField() {
        this.hasDueDate = !this.hasDueDate;
        if (!this.hasDueDate) {
            this.form.controls['dueDate'].setValue(null);
        }
    }

    #getStateName(stateId: string, templateId: string): string {
        return (this._dossierStatesMapService.get(templateId, stateId)?.name ||
            this._translateService.instant('dossier-state.placeholder')) as string;
    }

    #getStateColor(stateId: string, templateId: string): string {
        return this._dossierStatesMapService.get(templateId, stateId)?.color;
    }

    #patchFormValue() {
        this.#formValue.forEach(formValue => {
            this.form.patchValue({ [formValue.key]: formValue.value });
            if (formValue.disabled) this.form.get(formValue.key).disable();
        });
        this.initialFormValue = this.form.getRawValue();
    }

    async #closeDialogAndRedirectToDossier() {
        this._editDossierDialogRef.close();
        await this._router.navigate([this.dossier().dossiersListRouterLink]);
        this._toaster.success(_('edit-dossier-dialog.delete-successful'), {
            params: {
                dossierName: this.dossier().dossierName,
            },
        });
    }

    #filterInvalidDossierTemplates() {
        const dossier = untracked(this.dossier);
        this.dossierTemplates = this._dossierTemplatesService.all.filter(r => {
            if (dossier.dossierTemplateId === r.dossierTemplateId) {
                return true;
            }
            const notYetValid = !!r.validFrom && dayjs(r.validFrom).isAfter(dayjs());
            const notValidAnymore = !!r.validTo && dayjs(r.validTo).add(1, 'd').isBefore(dayjs());
            this._changeDetectorRef.markForCheck();
            return !(notYetValid || notValidAnymore) && r.isActive;
        });
    }

    #onDossierTemplateChange() {
        const dossierStateId = untracked(this.dossierStatusIdControl);
        const dossierTemplateId = untracked(this.dossierTemplateIdControl);
        if (!!dossierStateId && dossierTemplateId !== this.initialFormValue.dossierTemplateId) {
            this.form.controls.dossierStatusId.setValue(null);
        }
        const dossier = untracked(this.dossier);
        if (dossierTemplateId === this.initialFormValue.dossierTemplateId) {
            this.form.controls.dossierStatusId.setValue(dossier.dossierStatusId);
        }
        const states = untracked(this.states);
        if (isJustOne(states) || !dossier.isActive) {
            this.form.controls.dossierStatusId.disable();
        } else {
            this.form.controls.dossierStatusId.enable();
        }

        this._changeDetectorRef.markForCheck();
    }
}
