import { NgbModal, NgbModalOptions } from '@ng-bootstrap/ng-bootstrap';
import { Component, EventEmitter, Input, OnInit, Output, forwardRef, inject } from '@angular/core';
import { AbstractControl, ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator, Validators, FormsModule } from '@angular/forms';

import { EmployeeModel } from '../models/employee.model';
import { EmployeeSearchComponent } from './employeesearch.component';
import { EmployeeService } from '../../../providers/employee/employee.service';

@Component({
  standalone: true,
  selector: 'employee-control',
  templateUrl: './employeecontrol.component.html',
  styles: ['.full-width{width: calc(100% - 313px);}'],
  providers: [
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => EmployeeControlComponent), multi: true },
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => EmployeeControlComponent), multi: true }
  ],
  imports: [FormsModule]
})
export class EmployeeControlComponent implements OnInit, ControlValueAccessor, Validator 
{
  private readonly modalService = inject(NgbModal);
  private readonly service = inject(EmployeeService);

  private onTouched: () => void;
  private onChange: (value: any) => void;

  @Input() cssClass: string;
  @Input() required: boolean;
  @Input() submitted: boolean;
  @Input() disabled: boolean = false;
  @Output() employeeSelected = new EventEmitter<EmployeeModel>();

  public empName: string = '';
  public empCode: string = '';
  
  private employeeId: number = 0;
  private employee: EmployeeModel;
  private employeeType: number = 0;

  ngOnInit()
  {
    if (this.empCode && this.empCode.length >= 3)
    {
      this.onEmployeeCodeChanged();
    }
  }

  get getCssClass(): string
  {
    if (this.required && !this.disabled)
    {
      if ((this.cssClass || '').length > 0)
      {
        return (this.employeeId <= 0 && this.submitted) ? ` ${this.cssClass} invalid-custom-control` : ` ${this.cssClass}`;
      }
      else
      {
        return (this.employeeId <= 0 && this.submitted) ? 'invalid-custom-control' : '';
      }
    }
    else
    {
      return '';
    }
  }

  public onEmployeeCodeChanged(): void
  {
    if (this.empCode)
    {
      this.empCode = (this.empCode || '').toString();
      if (this.empCode.length >= 3)
      {
        this.service.getEmployeeByCode(this.employeeType, this.empCode).subscribe(
          {
            next: (response: any) =>
            {
              this.empName = (response.name || '');
              this.employeeId = response.employeeId;
              this.employeeType = response.employeeType;

              this.employee =
              {
                name: this.empName,
                employeeId: this.employeeId,
                code: (response.code || ''),
                employeeType: this.employeeType,
                joiningDate: response.joiningDate,
                contactNo: (response.contactNo || ''),
                designation: (response.designation || ''),
                emailAddress: (response.emailAddress || ''),
              };

              this.onChange(this.employee);
              this.onEmployeeSelected();
            },
            error: () =>
            {
              this.empName = '';
              this.employeeId = 0;
              this.initializeModel();

              this.onChange(this.employee);
              this.onEmployeeSelected();
            }
          });
      }
      else
      {
        this.empName = '';
        this.employeeId = 0;
        this.initializeModel();
      }
    }
    else
    {
      this.empName = '';
      this.employeeId = 0;
      this.initializeModel();

      this.onChange(this.employee);
      this.onEmployeeSelected();
    }
  }

  public showEmployees(): void
  {
    const modalOptions: NgbModalOptions = { keyboard: false, backdrop: 'static', centered: true, windowClass: 'gl-search-width' };
    const modalRef = this.modalService.open(EmployeeSearchComponent, modalOptions);
    modalRef.componentInstance.fromParent = { employeeType: this.employeeType };

    modalRef.result.then(
      (response) =>
      {
        if (response)
        {
          this.empCode = (response.code || '');
          this.empName = (response.name || '');
          this.employeeId = response.employeeId;
          this.employeeType = response.employeeType;

          this.employee =
          {
            code: this.empCode,
            name: this.empName,
            employeeType: this.employeeType,
            joiningDate: response.joiningDate,
            contactNo: (response.contactNo || ''),
            employeeId: +(response.employeeId || '0'),
            designation: (response.designation || ''),
            emailAddress: (response.emailAddress || ''),
          };
          if (this.employeeId && this.employeeId > 0 && this.empCode && this.empCode.length >= 3)
          {
            this.onChange(this.employee);
            this.onEmployeeSelected();
          }
        }
      },
      () =>
      {
        this.employeeId = 0;
        this.empCode = this.empName = '';
        this.initializeModel();

        this.onChange(this.employee);
      }
    );
  }

  private onEmployeeSelected(): void
  {
    this.employeeSelected.emit(this.employee);
  }

  private initializeModel(): void
  {
    this.employee =
    {
      code: '',
      name: '',
      contactNo: '',
      employeeId: 0,
      designation: '',
      emailAddress: '',
      joiningDate: null,
      employeeType: this.employeeType
    };
  }

  public writeValue(value: any): void
  {
    if (value)
    {
      this.empCode = value.code;
      this.employeeType = parseInt(value.employeeType || '0');
    }
    else
    {
      this.empCode = '';
      this.employeeId = 0;
      this.initializeModel();
    }
    this.onEmployeeCodeChanged();
  }

  public validate(control: AbstractControl): ValidationErrors | null
  {
    return this.required && !this.employeeId ? Validators.requiredTrue(control) : null;
  }

  public registerOnValidatorChange(fn: () => void): void
  {
    this.onChange = fn;
  }

  public registerOnChange(fn: (value: string) => void): void
  {
    this.onChange = fn;
  }

  public registerOnTouched(fn: () => void): void
  {
    this.onTouched = fn;
  }

  public setDisabledState(disabled: boolean)
  {
    this.disabled = disabled;
  }

  public onBlur(): void
  {
    this.onTouched();
  }
}
