import { ButtonSize, ButtonType, ButtonVariation } from '@af/digi-ng/_button/button';
import { FormSelectItem } from '@af/digi-ng/_form/form-select';
import {
  ChangeDetectionStrategy,
  Component,
  EventEmitter,
  Input,
  OnChanges,
  OnInit,
  Output,
  SimpleChanges,
} from '@angular/core';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { RoleEnum } from '@msfa-enums/role.enum';
import { EmployeeEditRequest } from '@msfa-models/api/employee-edit.request.model';
import { Employee } from '@msfa-models/employee.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import {
  TreeNode,
  TreeNodesSelectorService,
} from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
import { EmailValidator } from '@msfa-utils/validators/email.validator';
import { RequiredValidator } from '@msfa-utils/validators/required.validator';
import { TreeNodeValidator } from '@msfa-utils/validators/tree-node.validator';
import { EmployeeFormService } from '../services/employee-form.service';

@Component({
  selector: 'msfa-edit-employee-form',
  templateUrl: './edit-employee-form.component.html',
  styleUrls: ['./edit-employee-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditEmployeeFormComponent implements OnInit, OnChanges {
  @Input() employee: Employee;
  @Input() availableRoles: Role[];
  @Input() availableTjanster: Tjanst[];
  @Input() availableUtforandeVerksamheter: UtforandeVerksamhet[];
  @Input() errorWhileUpdating: CustomError;

  @Output() tjansterSelected = new EventEmitter<Tjanst[]>();
  @Output() closeError = new EventEmitter<void>();
  @Output() formSubmitted = new EventEmitter<EmployeeEditRequest>();

  readonly ButtonVariation = ButtonVariation;
  readonly ButtonType = ButtonType;
  readonly ButtonSize = ButtonSize;

  readonly emailFormControlName = 'email';
  readonly tjansterFormControlName = 'tjanster';
  readonly utforandeVerksamhetFormControlName = 'utforandeVerksamheter';
  readonly toggleAllUtforandeVerksamhetFormControlName = 'allaUtforandeVerksamheter';

  editEmployeeFormGroup: FormGroup | null = null;
  displayEditWithoutRolesDialog = false;
  displayPristineWarning = false;

  displayRolesDialog = false;

  selectableTjansterFormItems: Array<FormSelectItem> | null = null;

  constructor(
    private employeeFormService: EmployeeFormService,
    private utforandeVerksamheterService: UtforandeVerksamheterService,
    private treeNodesSelectorService: TreeNodesSelectorService
  ) {
    this.updateSelectableTjansterFormItems();
  }

  ngOnInit(): void {
    this.initializeEditEmployeeFormGroup();
    this.toggleTjanst();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.availableRoles) {
      this.initializeEditEmployeeFormGroup();
    }

    if (changes.availableTjanster) {
      this.updateSelectableTjansterFormItems();
    }

    if (changes.availableUtforandeVerksamheter) {
      this.editEmployeeFormGroup.patchValue(
        Object.fromEntries([
          [
            this.utforandeVerksamhetFormControlName,
            this.utforandeVerksamheterService.getTreeNodeDataFromUtforandeVerksamheter(
              this.availableUtforandeVerksamheter
            ),
          ],
        ])
      );

      this.updateUtforandeVerksamhetStatus();
    }
  }

  get emailFormControl(): AbstractControl | undefined {
    return this.editEmployeeFormGroup?.get(this.emailFormControlName);
  }

  get tjansterFormControl(): AbstractControl | undefined {
    return this.editEmployeeFormGroup?.get(this.tjansterFormControlName);
  }

  get rolesFormGroup(): AbstractControl {
    return this.editEmployeeFormGroup.get('roles');
  }

  get utforandeVerksamhetFormControl(): AbstractControl | undefined {
    return this.editEmployeeFormGroup?.get(this.utforandeVerksamhetFormControlName);
  }

  get toggleAllUtforandeVerksamhetFormControl(): AbstractControl | undefined {
    return this.editEmployeeFormGroup?.get(this.toggleAllUtforandeVerksamhetFormControlName);
  }

  private updateUtforandeVerksamhetStatus(): void {
    if (this.availableUtforandeVerksamheter && this.availableUtforandeVerksamheter.length > 0) {
      this.utforandeVerksamhetFormControl.enable();
      this.toggleAllUtforandeVerksamhetFormControl.enable();
      return;
    }

    this.utforandeVerksamhetFormControl.disable();
    this.toggleAllUtforandeVerksamhetFormControl.disable();
  }

  private updateSelectableTjansterFormItems(): void {
    this.selectableTjansterFormItems = this.availableTjanster?.map(tjanst => {
      return { name: tjanst.name, value: `${tjanst.tjanstId}` };
    });
  }

  private initializeEditEmployeeFormGroup(): void {
    const currentTjanst = this.employee.tjanster[0];
    const tjanstId = currentTjanst
      ? this.availableTjanster.find(tjanst => tjanst.code === currentTjanst.tjansteKod).tjanstId
      : null;

    this.editEmployeeFormGroup = new FormGroup({
      email: new FormControl(this.employee.email, [RequiredValidator('E-postadress'), EmailValidator()]),
      tjanster: new FormControl(tjanstId, [RequiredValidator('Tjänst')]),
      roles: this.employeeFormService.getRolesFormGroup(this.availableRoles, this.employee.roles),
      utforandeVerksamheter: new FormControl(
        this.utforandeVerksamheterService.getTreeNodeDataFromUtforandeVerksamheter(this.availableUtforandeVerksamheter),
        [
          TreeNodeValidator.IsValidTreeNode(
            this.utforandeVerksamheterService.hasSelectedUtforandeVerksamhet,
            'required',
            this.toggleAllUtforandeVerksamhetFormControl
          ),
        ]
      ),
      allaUtforandeVerksamheter: new FormControl(this.employee.allaUtforandeVerksamheter),
    });

    this.updateUtforandeVerksamhetStatus();
  }

  getFormControlName(role: Role): string {
    return this.employeeFormService.getFormControlName(role);
  }

  abortFormSubmit(): void {
    this.displayEditWithoutRolesDialog = false;
  }

  onFormSubmitted(saveWithoutRoles = false): void {
    if (!this.editEmployeeFormGroup) {
      return;
    }

    this.editEmployeeFormGroup.markAllAsTouched();

    if (this.editEmployeeFormGroup.invalid) {
      return;
    }

    if (this.editEmployeeFormGroup.pristine) {
      this.displayPristineWarning = true;
      return;
    }

    const roles = this.employeeFormService.getRolesFromFormGroup(this.rolesFormGroup, this.availableRoles);
    if (!roles.length && !saveWithoutRoles) {
      this.displayEditWithoutRolesDialog = true;
      return;
    }

    this.formSubmitted.emit({
      email: this.emailFormControl?.value as string,
      tjanstIds: this.employeeFormService
        .getSelectedTjanster(this.availableTjanster, +this.tjansterFormControl?.value)
        .map(tjanst => tjanst.tjanstId),
      roles: [
        ...new Set([
          ...this.employeeFormService.getRolesFromFormGroup(this.rolesFormGroup, this.availableRoles),
          RoleEnum.MSFA_Standard,
        ]),
      ],
      adressIds: this.toggleAllUtforandeVerksamhetFormControl.value
        ? []
        : this.utforandeVerksamheterService.getSelectedAdressIdsFromTreeNode(
            this.utforandeVerksamhetFormControl?.value
          ),
      allaUtforandeVerksamheter: !!this.toggleAllUtforandeVerksamhetFormControl.value,
    });
  }

  toggleTjanst(): void {
    if (this.tjansterFormControl.value) {
      this.tjansterSelected.emit(
        this.employeeFormService.getSelectedTjanster(this.availableTjanster, +this.tjansterFormControl.value)
      );
    }
  }

  openRolesDialog(): void {
    this.displayRolesDialog = true;
  }

  closeRolesDialog(): void {
    this.displayRolesDialog = false;
  }

  toggleAllUtforandeVerksamheter(selectAll: boolean): void {
    let treeNode: TreeNode = this.utforandeVerksamhetFormControl.value as TreeNode;

    treeNode = selectAll
      ? this.treeNodesSelectorService.getTreeNodeWithAllNodesSelected(treeNode)
      : this.treeNodesSelectorService.getTreeNodeWithNoNodesSelected(treeNode);

    this.editEmployeeFormGroup.patchValue(Object.fromEntries([[this.utforandeVerksamhetFormControlName, treeNode]]));
  }

  updateToggleAllUtforandeVerksamheter(): void {
    const hasSelectedAllLeafNodes = this.treeNodesSelectorService.hasSelectedAllLeafNodes(
      this.utforandeVerksamhetFormControl.value
    );

    this.editEmployeeFormGroup.patchValue(
      Object.fromEntries([[this.toggleAllUtforandeVerksamhetFormControlName, hasSelectedAllLeafNodes]])
    );
  }

  emitCloseError(): void {
    this.closeError.emit();
  }
}
