import {CommonModule} from '@angular/common';
import {
  AfterContentInit,
  ChangeDetectionStrategy,
  Component,
  ContentChild,
  EventEmitter,
  Input,
  Output,
  ViewEncapsulation,
} from '@angular/core';
import {FormFieldDirective} from '../form-field/form-field.directive';
import {IconButtonComponent} from '../icon-button/icon-button.component';
import {IconComponent} from '../icon/icon.component';
import {FormItemSize} from './form-item.model';

@Component({
  selector: 'nj-form-item',
  templateUrl: './form-item.component.html',
  styleUrls: ['./form-item.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  standalone: true,
  imports: [IconComponent, IconButtonComponent, FormFieldDirective, CommonModule]
})
export class FormItemComponent implements AfterContentInit {

  private readonly formItemClassName = 'nj-form-item';

  /**
   * @ignore
   */
  private _hasError: boolean;

  /**
   * @ignore
   */
  private _hasSuccess: boolean;

  /**
   * @ignore
   */
  private _hasHint: boolean;

  /**
   * @ignore
   */
  isPassword: boolean;

  /**
   * @ignore
   */
  isVisible = false;

  /**
   * @ignore
   */
  passwordNotice = '';

  /**
   * @ignore
   */
  passwordButtonLabel = '';

  /**
   * @ignore
   */
  isMultiline = false;

  /**
   * Input id and label for attribute, needed for focus to work properly
   */
  @Input() inputId: string;

  /**
   * Form item size
   */
  @Input() size: FormItemSize = 'medium';

  /**
   * Whether the form-item label is floating
   */
  @Input() isFloatingLabel = true;

  /**
   * Whether form-item is disabled or not
   */
  @Input() isDisabled: boolean;

  /**
   * Whether form-item is required or not
   */
  @Input() isRequired: boolean;

  /**
   * Whether form-item is in success state
   */
  @Input()
  set hasSuccess(value: boolean) {
    this._hasSuccess = value;
    this.setAriaAttributes();
  }

  get hasSuccess(): boolean {
    return this._hasSuccess;
  }

  /**
   * Whether form-item is in error state
   */
  @Input()
  set hasError(value: boolean) {
    this._hasError = value;
    this.setAriaAttributes();
  }

  get hasError(): boolean {
    return this._hasError;
  }

  /**
   * Whether the form-item has a hint substring
   */
  @Input()
  set hasHint(value: boolean) {
    this._hasHint = value;
    this.setAriaAttributes();
  }

  get hasHint(): boolean {
    return this._hasHint;
  }

  /**
   * Whether the form-item has a custom icon
   */
  @Input() hasCustomIcon: boolean;

  /**
   * Whether the form-item's icon (or custom icon) is clickable
   */
  @Input() isIconClickable = true;

  /**
   * Material icon name
   */
  @Input() iconName: string;

  /**
   * Additional form-item css classes
   */
  @Input() additionalClass: string = '';

  /**
   * Label for the button to toggle password visibility when password is hidden.
   * @example "Show password"
   */
  @Input() passwordButtonLabelShow?: string;

  /**
   * Label for the button to toggle password visibility when password is visible.
   * @example "Hide password"
   */
  @Input() passwordButtonLabelHide?: string;
  /**
   * Label to announce when password becomes visible.
   * @example "Password is visible"
   */
  @Input() passwordNoticeIsVisible?: string;

  /**
   * Label to announce when password becomes hidden.
   * @example "Password is hidden"
   */
  @Input() passwordNoticeIsHidden?: string;

  /**
   * Whether form-item is a select or not
   */
  @Input() isSelect: boolean;

  /**
   * Outputs icon click
   */
  @Output() iconClick: EventEmitter<MouseEvent> = new EventEmitter<
    MouseEvent
  >();

  /**
   * Outputs icon keydown
   */
  @Output() iconKeydown: EventEmitter<KeyboardEvent> = new EventEmitter<
    KeyboardEvent
  >();

  /**
   * Outputs icon click
   */
  @Output() wrapperClick: EventEmitter<MouseEvent> = new EventEmitter<
    MouseEvent
  >();

  /**
   * @ignore
   */
  @ContentChild(FormFieldDirective) formField: FormFieldDirective;

  ngAfterContentInit() {
    const tagName = this.formField?.tagName?.toLowerCase();
    this.isPassword = this.formField?.type === 'password';
    this.isMultiline = tagName === 'textarea';
    this.passwordButtonLabel = this.passwordButtonLabelShow;
    this.setAriaAttributes();
    if (this.isRequired) {
      this.formField.element.setAttribute('required', 'required');
    }
  }

  /**
   * @ignore
   */
  iconClickHandler(event: MouseEvent) {
    if (!this.isIconClickable) {
      return;
    }
    this.iconClick.emit(event);
  }

  /**
   * @ignore
   */
  iconKeydownHandler(event: KeyboardEvent) {
    event?.preventDefault();
    if (!this.isIconClickable) {
      return;
    }
    this.iconKeydown.emit(event);
  }

  /**
   * @ignore
   */
  toggleVisibility() {
    if (this.isVisible) {
      this.formField.type = 'password';
      this.passwordNotice = this.passwordNoticeIsHidden;
      this.passwordButtonLabel = this.passwordButtonLabelShow;
    } else {
      this.formField.type = 'text';
      this.passwordNotice = this.passwordNoticeIsVisible;
      this.passwordButtonLabel = this.passwordButtonLabelHide;
    }
    this.isVisible = !this.isVisible;
  }

  /**
   * @ignore
   */
  getSubscriptId(): string {
    return `${this.inputId}-subscript`;
  }

  /**
   * @ignore
   */
  setAriaAttributes() {
    if (this.formField?.element) {
      if (this.hasError) {
        this.formField.element.setAttribute('aria-invalid', 'true');
      }

      if (this.hasError || this.hasSuccess || this.hasHint) {
        this.formField.element.setAttribute('aria-describedby', this.getSubscriptId());
      }
    }
  }

  /**
   * @ignore
   */
  isCustomSelect(): boolean {
    const type = this.formField?.type;
    return this.isSelect && type === 'text';
  }

  /**
   * @ignore
   */
  getFormItemSizeClass(): string {
    let sizeModifier: string;
    switch (this.size) {
      case 'small':
        sizeModifier = 'sm';
        break;
      case 'large':
        sizeModifier = 'lg';
        break;
      case 'xlarge':
        sizeModifier = 'xl';
        break;
      default:
        break;
    }
    return sizeModifier ? `${this.formItemClassName}--${sizeModifier}` : '';
  }
}
