import { AuthService } from './../../../security/auth-service';
import { bindingMode, computedFrom, Container, TaskQueue } from 'aurelia-framework';
import { bindable, customElement } from "aurelia-templating";
import { EditingModeEnum } from '../../../vm/editing-mode-enum';
import { Role, User, UserRole } from '../../../model/common-model';
import { ServiceBase } from '../../../data/service-base';
import { EntityTypeNames, RolesMode } from '../../../constants/constants';
import { DataFormat } from 'select2';

@customElement('user-base-form')
export class UserBaseForm {
  @bindable({ defaultBindingMode: bindingMode.toView })
  private rolesMode: RolesMode = 'single';
  @bindable({ defaultBindingMode: bindingMode.toView })
  private editingMode: EditingModeEnum;
  @bindable({ defaultBindingMode: bindingMode.toView })
  private canEditUser: boolean = true;
  @bindable({ defaultBindingMode: bindingMode.toView })
  private maxColumns: number = 1 | 2 | 3 | 4;

  @bindable({ defaultBindingMode: bindingMode.twoWay })
  private user: User;
  @bindable()
  private canAddOrUpdate: boolean = false;

  @bindable()
  private languages: Array<{ value: string, denominationKey: string }> = [
    { value: 'fr', denominationKey: 'common:general.french' },
    { value: 'en', denominationKey: 'common:general.english' },
    { value: 'nl', denominationKey: 'common:general.dutch' },
  ];

  @bindable()
  private languageValuesToRemove: Array<string> = [];

  protected roleService: ServiceBase<Role>;
  protected userRoleService: ServiceBase<UserRole>;

  private authService: AuthService;
  private singleRoleSelection: DataFormat;
  private originalUserRole: UserRole;

  @computedFrom('maxColumns')
  private get columnClass(): string {
    switch (this.maxColumns) {
      case 2: return 'm6';
      case 3: return 'm6 l4';
      case 4: return 'm6 l3';
    }
    return '';
  }

  @computedFrom('editingMode')
  private get isCreationMode(): boolean {
    return this.editingMode == EditingModeEnum.Create;
  }

  @computedFrom('languageValuesToRemove.length', 'languages.length')
  private get languagesToShow(): Array<{ value: string, denominationKey: string }> {
    return this.languages.filter(l => !this.languageValuesToRemove.some(r => r == l.value));
  }

  public attached() {
    this.authService = Container.instance.get(AuthService);
    if (this.rolesMode != 'none') {
      this.roleService = new ServiceBase<Role>(EntityTypeNames.Role);
      this.roleService.gridDataSource.expands = ['permissions'];
      this.userRoleService = new ServiceBase<UserRole>(EntityTypeNames.UserRole);
      this.originalUserRole = null;
    }
  }

  private onSingleRoleSelectReady() {
    if (this.rolesMode == 'single' && this.user?.roles?.length > 0) {
      this.originalUserRole = this.user?.roles[0];
      this.singleRoleSelection = {
        id: this.originalUserRole.roleId,
        text: this.originalUserRole.role.name._translation
      }
    }
  }

  private async onSingleRoleSelected() {
    const selectedId = this.singleRoleSelection?.id || this.singleRoleSelection;
    // Do nothing on init (re-selecting existing role)
    if (this.user?.roles?.find(x => x.roleId == selectedId)) {
      return;
    }

    // Delete and re-create as userId-roleId is PK (update of either field possible)
    if (this.user?.roles?.length > 0) {
      this.user.roles.forEach(x => x.entityAspect.entityState.isAdded() ? x.entityAspect.setDetached() : x.entityAspect.setDeleted());
    }
    // If going back to original value, recover previous entity
    if (this.originalUserRole != null && selectedId == this.originalUserRole?.roleId) {
      this.originalUserRole.entityAspect.setUnchanged();
      this.user.roles.push(this.originalUserRole);
    } else {
      let newRole = await this.userRoleService.createEntity({ userId: this.user.id, roleId: selectedId as number });
      this.user.roles.push(newRole);
    }
  }
}