import { Directive, ContentChild, Optional, Self, AfterContentInit, Inject, InjectionToken, ChangeDetectorRef, Host } from '@angular/core';
import { NgControl, FormControlName, FormControlDirective, AbstractControl } from '@angular/forms';
import { SEComponent } from '@delon/abc/se';
import { NzFormControlComponent, NzFormItemComponent } from 'ng-zorro-antd/form';
import { filter } from 'rxjs/operators';

export const AUTO_ERROR_TIP_MAP = new InjectionToken<Record<string, string>>('AUTO_ERROR_TIP_MAP');
export const AUTO_ERROR_TIP_KEY = new InjectionToken<string>('AUTO_ERROR_TIP_KEY');

const defaultErrorTipKep = 'errorTip';

@Directive({
    selector: '[autoErrorTip]'
})
export class AutoErrorTipDirective implements AfterContentInit {
    @ContentChild(NgControl, { static: false }) ngControl!: FormControlName | FormControlDirective;
    private errorTipKey: string;
    private errorTipMap: Record<string, string>;
    constructor(
        @Optional() @Self() private nzFormControl: NzFormControlComponent,
        @Optional() @Host() private nzFormItemComponent: NzFormItemComponent,
        @Optional() @Inject(AUTO_ERROR_TIP_KEY) errorTipKey: string,
        @Optional() @Inject(AUTO_ERROR_TIP_MAP) errorTipMap: Record<string, string>,
        @Optional() @Self() private seControl: SEComponent
    ) {
        this.errorTipKey = errorTipKey || defaultErrorTipKep;
        this.errorTipMap = { ...(errorTipMap || {}) };
    }

    ngAfterContentInit(): void {
        if ((this.nzFormControl || this.seControl) && this.ngControl) {
            this.ngControl.statusChanges!.pipe(filter(status => status === 'INVALID')).subscribe(() => {
                const errors = this.ngControl.errors || {};
                Object.entries(errors).some(([key, value]) => {
                    const errorTip = value[this.errorTipKey];
                    if (!!errorTip) {
                        if (this.nzFormControl) {
                            this.nzFormControl.innerTip = errorTip;
                            this.nzFormControl.nzErrorTip = errorTip;
                        }
                        if (this.seControl) {
                            this.seControl.error = errorTip;
                        }
                    }
                    return !!errorTip;
                });
                if (this.nzFormControl && this.nzFormItemComponent) {
                    this.nzFormItemComponent.setWithHelpViaTips(!!this.nzFormControl.innerTip);
                }
            });
        }
    }
}
