import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
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 { Permission } from 'src/app/model/entities/role';
import {
  ApiKey,
  ApiKeyCreateInput,
  ApiKeyUpdateInput,
} from 'src/app/model/entities/api-key';
import { ApiKeysDataService } from 'src/app/modules/admin/administration/api-keys/api-keys.data.service';

@Component({
  selector: 'app-api-key-form-page',
  templateUrl: './api-key-form-page.component.html',
  styleUrl: './api-key-form-page.component.scss',
})
export class ApiKeyFormPageComponent extends FormPageBase<
  ApiKey,
  ApiKeyCreateInput,
  ApiKeyUpdateInput,
  ApiKeysDataService
> {
  permissionGroups: { [key: string]: Permission[] } = {};
  allPermissions: Permission[] = [];

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

        return;
      }

      this.dataService
        .load([{ id: { equal: this.nodeId } }])
        .subscribe(apiKey => {
          this.node = apiKey.nodes[0];
          this.setForm(this.node);
        });
    });
  }

  async initializePermissions() {
    const permissions = await firstValueFrom(
      this.dataService.getAllPermissions()
    );
    this.allPermissions = permissions;
    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(): ApiKey {
    return {} as ApiKey;
  }

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

  setForm(node?: ApiKey) {
    this.form.controls['id'].setValue(node?.id);
    this.form.controls['identifier'].setValue(node?.identifier);

    if (!node) return;

    const permissions = node.permissions ?? [];

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

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

  getUpdateInput(): ApiKeyUpdateInput {
    if (!this.node?.id) {
      throw new Error('Node id is missing');
    }

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

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

  update(apiKey: ApiKeyUpdateInput): void {
    this.dataService.update(apiKey).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;
}
