import { Component } from '@angular/core';
import {
  Permission,
  Role,
  RoleCreateInput,
  RoleUpdateInput,
} from 'src/app/model/entities/role';
import { InputSwitchChangeEvent } from 'primeng/inputswitch';
import { ToastService } from 'src/app/service/toast.service';
import { firstValueFrom } from 'rxjs';
import { FormPageBase } from 'src/app/core/base/form-page-base';
import { RolesDataService } from 'src/app/modules/admin/administration/roles/roles.data.service';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-role-form-page',
  templateUrl: './role-form-page.component.html',
  styleUrl: './role-form-page.component.scss',
})
export class RoleFormPageComponent extends FormPageBase<
  Role,
  RoleCreateInput,
  RoleUpdateInput,
  RolesDataService
> {
  permissionGroups: { [key: string]: Permission[] } = {};
  allPermissions: Permission[] = [];

  constructor(
    private toast: ToastService,
    private translate: TranslateService
  ) {
    super();
    this.initializePermissions().then(() => {
      if (!this.nodeId) {
        this.node = this.new();
        this.setForm(this.node);

        return;
      }

      this.dataService.loadById(this.nodeId).subscribe(role => {
        this.node = role;
        this.setForm(this.node);
      });
    });
  }

  async initializePermissions() {
    const permissions = await firstValueFrom(
      this.dataService.getAllPermissions()
    );
    this.allPermissions = permissions.map(x => {
      const key = `permission_descriptions.${x.name}`;
      const description = this.translate.instant(key);
      x.description = description === key ? undefined : description;
      return x;
    });
    this.permissionGroups = permissions.reduce(
      (acc, p) => {
        const group = p.name.includes('.') ? p.name.split('.')[0] : p.name;

        if (!acc[group]) {
          acc[group] = [];
        }
        acc[group].push(p);
        return acc;
      },
      {} as { [key: string]: Permission[] }
    );

    permissions.forEach(p => {
      this.form.addControl(p.name, new FormControl<boolean>(false));
    });
  }

  new(): Role {
    return {} as Role;
  }

  buildForm() {
    this.form = new FormGroup({
      id: new FormControl<number | undefined>(undefined),
      name: new FormControl<string | undefined>(undefined, Validators.required),
      description: new FormControl<string | undefined>(undefined),
    });
    this.form.controls['id'].disable();
  }

  setForm(node?: Role) {
    this.form.controls['id'].setValue(node?.id);
    this.form.controls['name'].setValue(node?.name);
    this.form.controls['description'].setValue(node?.description);

    if (!node) return;

    const permissions = node.permissions ?? [];

    permissions.forEach(p => {
      this.form.controls[p.name].setValue(true);
    });
  }

  getCreateInput(): RoleCreateInput {
    return {
      name: this.form.controls['name'].pristine
        ? undefined
        : (this.form.controls['name'].value ?? undefined),
      description: this.form.controls['description'].pristine
        ? undefined
        : (this.form.controls['description'].value ?? undefined),
      permissions: this.allPermissions.filter(
        p => this.form.controls[p.name].value
      ),
    };
  }

  getUpdateInput(): RoleUpdateInput {
    return {
      id: this.form.controls['id'].value,
      name: this.form.controls['name'].pristine
        ? undefined
        : this.form.controls['name'].value,
      description: this.form.controls['description'].pristine
        ? undefined
        : this.form.controls['description'].value,
      permissions: this.allPermissions.filter(
        p => this.form.controls[p.name].value
      ),
    };
  }

  create(role: RoleCreateInput): void {
    this.dataService.create(role).subscribe(() => {
      this.spinner.hide();
      this.toast.success('action.created');
      this.close();
    });
  }

  update(role: RoleUpdateInput): void {
    this.dataService.update(role).subscribe(() => {
      this.spinner.hide();
      this.toast.success('action.updated');
      this.close();
    });
  }

  toggleGroup(event: InputSwitchChangeEvent, group: string) {
    this.permissionGroups[group].forEach(p => {
      this.form.controls[p.name].setValue(event.checked);
    });
  }

  isGroupChecked(group: string) {
    return this.permissionGroups[group].every(
      p => this.form.controls[p.name].value
    );
  }

  protected readonly Object = Object;
}
