import {
  ChangeDetectionStrategy,
  Component,
  computed,
  effect,
  input,
  signal
} from '@angular/core';
import { AbstractControl } from '@angular/forms';

import {
  FormValidationMessage,
  ValidationMessageMap
} from '../form-validation-message/form-validation-message';
import { TooltipDirective } from '../../../directives/tooltip/tooltip.directive';

export type FormLabelPosition = 'top' | 'left' | 'hidden';

@Component({
  selector: 'app-form-field',
  standalone: true,
  imports: [FormValidationMessage, TooltipDirective],
  templateUrl: './form-field.html',
  styleUrl: './form-field.scss',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class FormField {
  readonly label = input.required<string>();

  readonly inputId = input.required<string>();

  readonly control = input<AbstractControl | null>(null);

  readonly required = input(false);

  readonly disabled = input(false);

  readonly description = input<string | null>(null);

  readonly hint = input<string | null>(null);
  readonly help = input<string | null>(null);

  readonly showHelpIcon = computed(() => {
    return !!this.help()?.trim();
  });

  readonly resolvedHelp = computed(() => {
    return this.help()?.trim() ?? '';
  });

  readonly labelPosition = input<FormLabelPosition>('top');

  readonly hideLabel = input(false);

  readonly floating = input(false);

  readonly forceFloat = input(false);

  readonly hideValidation = input(false);

  readonly showValidationWhenDirty = input(false);

  readonly submitAttempted = input(false);

  readonly validationMessages =
    input<ValidationMessageMap>({});

  readonly wrapperClass = input('');

  readonly labelClass = input('');

  readonly contentClass = input('');

  readonly descriptionClass = input(
    'mb-2 text-[0.75rem] leading-4 text-textmuted'
  );

  readonly hintClass = input(
    'mt-1 text-[0.75rem] leading-4 text-textmuted'
  );

  readonly requiredClass = input(
    'ms-0.5 text-danger'
  );

  private readonly controlStateVersion = signal(0);

  constructor() {
    effect((onCleanup) => {
      const control = this.control();

      if (!control) {
        return;
      }

      const statusSubscription = control.statusChanges.subscribe(() => {
        this.controlStateVersion.update(value => value + 1);
      });

      const valueSubscription = control.valueChanges.subscribe(() => {
        this.controlStateVersion.update(value => value + 1);
      });

      const eventsSubscription = control.events?.subscribe(() => {
        this.controlStateVersion.update(value => value + 1);
      });

      onCleanup(() => {
        statusSubscription.unsubscribe();
        valueSubscription.unsubscribe();
        eventsSubscription?.unsubscribe();
      });
    });
  }

  readonly validationId = computed(
    () => `${this.inputId()}-validation`
  );

  readonly hintId = computed(
    () => `${this.inputId()}-hint`
  );

  readonly descriptionId = computed(
    () => `${this.inputId()}-description`
  );

  readonly hasVisibleError = computed(() => {
    this.controlStateVersion();

    const control = this.control();

    if (!control?.invalid) {
      return false;
    }

    return (
      this.submitAttempted() ||
      (this.showValidationWhenDirty() && control.dirty)
    );
  });

  readonly hasValue = computed(() => {
    this.controlStateVersion();

    const control = this.control();

    if (!control) {
      return false;
    }

    const value = control.value;

    return value !== null && value !== undefined && value !== '';
  });

  readonly resolvedWrapperClass = computed(() => {
    return [
      this.labelPosition() === 'left'
        ? 'grid grid-cols-12 items-start gap-x-4 gap-y-2'
        : '',
      this.wrapperClass()
    ]
      .filter(Boolean)
      .join(' ');
  });

  readonly resolvedLabelClass = computed(() => {
    return [
      'form-label',
      'mb-1.5 block',
      this.labelPosition() === 'left'
        ? 'col-span-12 md:col-span-4 md:mb-0 md:pt-2'
        : '',
      this.disabled()
        ? 'cursor-not-allowed opacity-60'
        : '',
      this.labelClass()
    ]
      .filter(Boolean)
      .join(' ');
  });

  readonly resolvedContentClass = computed(() => {
    return [
      this.labelPosition() === 'left'
        ? 'col-span-12 md:col-span-8'
        : '',
      this.contentClass()
    ]
      .filter(Boolean)
      .join(' ');
  });

  readonly showLabel = computed(() => {
    return (
      !this.hideLabel() &&
      this.labelPosition() !== 'hidden'
    );
  });

  readonly showHint = computed(() => {
    return !!this.hint() && !this.hasVisibleError();
  });
}
