import { CustomLogger } from '../../../modules/custom-logger';
import { AuthService } from '../../../security/auth-service';
import { HttpClient } from 'aurelia-fetch-client';
import { EntityTypeNames } from '../../../constants/constants';
import { ServiceBase } from '../../../data/service-base';
import { User } from '../../../model/common-model';
import { FloatingBoxViewModel } from "../../../modules/dialogs/floating-box";
import { BindingEngine, computedFrom } from 'aurelia-binding';
import { FilterQueryOp, Predicate } from 'breeze-client';
import { I18N } from 'aurelia-i18n';
import { Container } from 'aurelia-framework';
import { ValidationController, ValidationRules } from 'aurelia-validation';
import { Config } from '../../../config';


export class UpdateUsernameFloatingBox extends FloatingBoxViewModel {

    private config: Config;
    private i18n: I18N;
    private controller: ValidationController;
    private bindingEngine: BindingEngine;
    private httpClient: HttpClient;
    private authService: AuthService;
    private logger: CustomLogger;

    private newUserEmail: string = "";
    private error: string;

    private userService: ServiceBase<User>;

    constructor(private entity: User) {
        super("./update-username-floating-box.html");

        this.userService = new ServiceBase(EntityTypeNames.User);

        this.i18n = Container.instance.get(I18N);
        this.controller = Container.instance.get(ValidationController);
        this.bindingEngine = Container.instance.get(BindingEngine);
        this.config = Container.instance.get(Config);
        this.httpClient = Container.instance.get(HttpClient);
        this.authService = Container.instance.get(AuthService);
        this.logger = new CustomLogger();

        this.initValidation();
        this.initObservers();
    }

    private initValidation() {
        ValidationRules.customRule('validation-email', (val, obj) => {
            if (val?.length > 0) {
                return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(val.trim());
            }
            return true;
        }, this.i18n.tr('common:user.errorInvalidEmail'));

        ValidationRules
            .ensure('newUserEmail')
            .satisfiesRule('validation-email')
            .on(this);
    }

    private initObservers() {
        this.disposables.push(
            this.bindingEngine.propertyObserver(this, "newUserEmail").subscribe((newValue, oldValue) => {
                if (newValue != oldValue) this.error = null;
            })
        );
    }

    protected async save() {
        this.error = null;
        if (await this.isEmailValid()) {
            let result = await this.httpClient.post(`${this.config.globalConfig.remoteServiceName}/api/auth/UpdateUsername`, JSON.stringify({
                UserId: this.entity.id,
                NewUsername: this.newUserEmail
            }));

            if (!result.ok) {
                let resultJson = await result.json();
                this.error = resultJson.Message;
            } else {
                await this.userService.getEntityById(this.entity.id);
                let successMessage = this.authService.usernameType == 'email' ? this.i18n.tr("user.emailUpdated", { ns: "common" }) : this.i18n.tr("user.usernameUpdated", { ns: "common" })
                this.logger.Log(successMessage, null, null, true);
                this.dialogController.ok();
            }
        }
    }

    private async isEmailValid(): Promise<boolean> {
        let validationResult = await this.controller.validate({ object: this });
        if (!validationResult.valid) {
            this.error = validationResult.results.map(r => r.message).join("; ");
            return false;
        }

        let existingUser = await this.userService.firstEntity(new Predicate("username", FilterQueryOp.Equals, this.newUserEmail));
        if (existingUser != null) {
            this.error = this.i18n.tr("common:user.errorEmailAlreadyExists");
            return false;
        }
        return true;
    }

    @computedFrom("newUserEmail", "entity.username")
    public get canSave() {
        return this.newUserEmail != this.entity.username;
    }

    @computedFrom("authService.usernameType")
    public get dialogTitle(): string {
        return this.authService.usernameType == 'email' ? this.i18n.tr("user.updateEmail", { ns: 'common' }) : this.i18n.tr("user.updateUsername", { ns: 'common' });
    }

    @computedFrom("authService.usernameType")
    public get inputLabel(): string {
        return this.authService.usernameType == 'email' ? this.i18n.tr("user.newEmail", { ns: 'common' }) : this.i18n.tr("user.newUsername", { ns: 'common' });
    }
}