import { Component, OnInit } from '@angular/core';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { IProjectModel } from '@fleio-api/openstack/project/model/project.model';
import { UntypedFormArray, UntypedFormBuilder, Validators } from '@angular/forms';
import { ProjectsApiService } from '@fleio-api/openstack/project/projects-api.service';
import { NotificationService } from '@shared/ui-api/notification.service';
import { IRoleModel } from '@fleio-api/client-user/roles/model/role.model';
import { IApiUserModel } from '@fleio-api/openstack/model/api-user.model';
import { Observable, of } from 'rxjs';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';

@Component({
  selector: 'app-project-role-assignments',
  templateUrl: './project-role-assignments.component.html',
  styleUrl: './project-role-assignments.component.scss'
})
export class ProjectRoleAssignmentsComponent extends DetailsFormBase<IProjectModel> implements OnInit {
  roleAssignmentForm = this.formBuilder.group({
    assignments: this.formBuilder.array([]),
  });
  assignedRoles: {
    [user_name: string]: Array<IRoleModel>,
  };
  availableRoles: Array<IRoleModel>;
  apiUsers: Array<IApiUserModel>;
  assignments = this.roleAssignmentForm.get('assignments') as UntypedFormArray;
  loading = false;
  userUnselectedPlaceholder = $localize`Select user ...`;
  userSelectedPlaceholder = $localize`User`;
  userOptionsSwitchMap: (search: string) => Observable<any>;
  apiUserNamesToID = null;

  constructor(
    private formBuilder: UntypedFormBuilder,
    private projectsApiService: ProjectsApiService,
    private notificationService: NotificationService,
  ) {
    super();
  }

  protected tabActivated() {
    super.tabActivated();
    this.projectsApiService.getAvailableRoles().subscribe(value => {
      this.availableRoles = value.available_roles;
      this.refreshRoles();
    });
  }

  ngOnInit(refreshTimerInterval?: number) {
    super.ngOnInit(refreshTimerInterval);
    if (this.objectController) {
      this.objectController.actionCallback = () => this.saveAssignments();
    }

    this.userOptionsSwitchMap = (search) => {
      const lowerCaseValue = search.toLocaleLowerCase();
      const value = this.assignments.getRawValue();
      return of(this.apiUsers.filter(
        (apiUser) => {
          let alreadySelected = false;
          value.forEach(assignment => {
            let selectedName: string;
            if (typeof assignment.user !== 'string' && assignment.user?.name) {
              selectedName = assignment.user.name;
            } else {
              selectedName = assignment.user;
            }
            if (apiUser.name === selectedName) {
              alreadySelected = true;
            }
          });
          return !alreadySelected && apiUser.name.toLocaleLowerCase().includes(lowerCaseValue);
        }
      ));
    };
  }

  public addRoleAssignment() {
    return this.assignments.push(this.createRoleAssignment());
  }

  public removeRoleAssignment(index) {
    this.assignments.removeAt(index);
  }

  public saveAssignments() {
    this.validate();
    if (this.formGroup.invalid) {
      this.displayControlErrors();
      return of(null);
    }

    this.objectController.loading = true;
    const value = this.assignments.getRawValue();
    const submitValue = [];
    value.forEach(assignment => {
      if (typeof assignment.user !== 'string' && assignment.user?.name) {
        assignment.user = assignment.user.name;
      }
      assignment.user_id = this.apiUserNamesToID[assignment.user];
      submitValue.push(assignment);
    });
    this.projectsApiService.updateRoleAssignments(
      this.object.id, submitValue
    ).subscribe({
      next: value => {
        this.notificationService.showMessage(value.detail);
        this.refreshRoles();
      }, error: (error) => {
        if (error.error) {
          this.setErrors(error.error);
        }
      }
    }).add(() => {
      this.objectController.loading = false;
    });
    return of(null);
  }

  private refreshRoles() {
    this.loading = true;
    this.projectsApiService.getRoleAssignments(this.object.id).subscribe({
      next: value => {
        this.apiUsers = value.api_users;
        this.assignedRoles = value.role_assignments;
        this.apiUserNamesToID = value.api_user_names_to_id;
        this.assignments.clear();
        Object.keys(this.assignedRoles).forEach(key => {
          let assignedRoles = [];
          for (let role of this.assignedRoles[key]) {
            assignedRoles.push((role as IRoleModel).name);
          }
          return this.assignments.push(this.createRoleAssignment(key, assignedRoles, true));
        });
        this.loading = false;
      },
      error: error => {
        this.notificationService.showMessage(
          error?.error?.detail || $localize`Unable to retrieve roles`
        );
      }
    });
  }

  private createRoleAssignment(user = null, roles = [], disableUser = false) {
    const group = this.formBuilder.group({
      user: [user, [Validators.required, ValidatorsHelper.requiredObjectValidator]],
      roles: [roles, Validators.required],
      user_id: [],
    });
    if (disableUser) {
      group.controls.user.disable();
    }
    group.valueChanges.subscribe(value => {
      if (value && value?.user?.id) {
        this.apiUserNamesToID[value.user.name] = value.user.id;
      }
    });
    return group;
  }

}
