import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {EmployeePermission, mapped_permissions} from "../../model/employee";
import {FormControl} from "@angular/forms";
import {AccountService} from "../../../accounts/services/account.service";

@Component({
  selector: 'cre-permissions-field',
  templateUrl: './permissions-field.component.html',
  styleUrls: ['./permissions-field.component.sass']
})
export class PermissionsFieldComponent implements OnInit {
  @Input() enabledPermissions: EmployeePermission[]
  @Input() title = 'Permissions'
  @Input() required = true

  permissionControls: any = {view: [], edit: [], remove: [], other: []}
  @ViewChild('permissions', {static: true}) permissionsDiv: HTMLDivElement
  permissionsValid = true

  constructor(
    private accountService: AccountService
  ) {
  }

  ngOnInit(): void {
    this.mapPermissions('view')
    this.mapPermissions('edit')
    this.mapPermissions('remove')
    this.mapPermissions('other')

    if (this.enabledPermissions) {
      this.enabledPermissions.forEach(p => {
        const control = this.findPermissionControl(p)
        control.control.setValue(true)
        this.togglePermission(control, true)
      })
    }
  }

  togglePermission(permission: any, bypassValue?: boolean) {
    if (permission.control.enabled) {
      const allImpliedControls = this.getImpliedPermissionControls(permission)
      allImpliedControls.forEach(c => {
        c.control.setValue(bypassValue === undefined ? !permission.control.value : bypassValue)
        if (bypassValue === undefined) {
          permission.control.value ? c.control.enable() : c.control.disable()
        } else {
          !bypassValue ? c.control.enable() : c.control.disable()
        }
        c.enabledFromParent = true
      })
    }
  }

  valid() {
    if (this.checkPermissionsValid()) {
      // @ts-ignore
      this.permissionsDiv.nativeElement.classList.remove('invalid')
      this.permissionsValid = true

      return true
    }
    // @ts-ignore
    this.permissionsDiv.nativeElement.classList.add('invalid')
    this.permissionsValid = false
    return false
  }

  get allEnabledPermissions(): EmployeePermission[] {
    return this.allPermissionControls().filter(p => p.control.value).map(p => p.permission)
  }

  private checkPermissionsValid() {
    return !this.required || this.allPermissionControls().map(p => p.control).filter(c => c.value).length > 0
  }

  private mapPermissions(type: string) {
    mapped_permissions[type].forEach(p => this.permissionControls[type].push({
      permission: p.permission,
      impliedPermissions: p.impliedPermissions,
      description: p.description,
      control: new FormControl({value: false, disabled: !this.accountService.hasPermission(p.permission)})
    }))
  }

  private allPermissionControls(): any[] {
    // @ts-ignore
    return Object.values(this.permissionControls).flatMap(p => p)
  }

  private findPermissionControl(permission: EmployeePermission): any {
    return this.allPermissionControls().filter(p => p.permission === permission)[0]
  }

  private getImpliedPermissionControls(permissionControl: any): any[] {
    const impliedPermissions = []
    if (permissionControl.impliedPermissions && permissionControl.impliedPermissions.length > 0) {
      permissionControl.impliedPermissions.map(p => {
        const permission = this.findPermissionControl(p)
        impliedPermissions.push(permission)
        this.getImpliedPermissionControls(permission).forEach(i => {
          if (impliedPermissions.indexOf(i) < 0) {
            impliedPermissions.push(i)
          }
        })
      })
    }
    return impliedPermissions
  }
}
