import {
  ChangeDetectionStrategy,
  Component,
  effect,
  input,
  output,
  untracked,
} from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';

import { ButtonComponent } from '@isa/ui/buttons';
import {
  InputControlDirective,
  TextFieldClearComponent,
  TextFieldComponent,
  TextFieldContainerComponent,
  TextFieldErrorsComponent,
} from '@isa/ui/input-controls';
import { ScannerButtonComponent } from '@isa/shared/scanner';
import { RequestStatus } from './remission-start-dialog.component';

/**
 * Component for assigning a package number in the remission process.
 *
 * This component provides the second step of the remission workflow, allowing users to:
 * - Manually input a 14-digit package number
 * - Scan a package number using the integrated scanner
 * - Validate package number format (14-digit requirement)
 * - Handle server-side validation errors
 *
 * The component uses reactive forms for input validation and handles server-side
 * validation errors through the RequestStatus input. It emits the package number
 * when the form is submitted successfully, or undefined if validation fails.
 *
 * @example
 * ```html
 * <remi-assign-package-number
 *   [assignPackageLoading]="requestStatus"
 *   (assignPackageNumber)="onAssignPackageNumber($event)"
 * />
 * ```
 *
 * @example
 * ```typescript
 * // Handling the output event
 * onAssignPackageNumber(packageNumber: string | undefined): void {
 *   if (packageNumber) {
 *     // Package number provided and validated
 *     console.log('Package number:', packageNumber);
 *   } else {
 *     // Validation failed or user cancelled
 *     console.log('Package assignment cancelled or invalid');
 *   }
 * }
 * ```
 */
@Component({
  selector: 'remi-assign-package-number',
  templateUrl: './assign-package-number.component.html',
  styleUrl: './assign-package-number.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    ReactiveFormsModule,
    ButtonComponent,
    InputControlDirective,
    TextFieldClearComponent,
    TextFieldComponent,
    TextFieldContainerComponent,
    TextFieldErrorsComponent,
    ScannerButtonComponent,
  ],
})
export class AssignPackageNumberComponent {
  /** Input flag indicating if the dialog is opened for package assignment only */
  assignPackageOnly = input<boolean>(false);

  /**
   * Input signal containing the current request status for the assign package operation.
   * Used to display loading states and handle server-side validation errors.
   * When invalidProperties contains 'PackageNumber', the form control is updated with the error.
   */
  assignPackageLoading = input<RequestStatus>({ loading: false });

  /**
   * Output signal emitted when user completes the package assignment step.
   * Emits the validated package number string if successful, or undefined if validation fails
   * or the user cancels the operation.
   */
  assignPackageNumber = output<string | undefined>();

  /**
   * Form control for the package number input field.
   *
   * Validation rules:
   * - Required: Package number must be provided
   * - Pattern: Must be exactly 14 digits (/^\d{14}$/)
   *
   * The control also handles server-side validation errors received through
   * the assignPackageLoading input signal.
   */
  control = new FormControl<string | undefined>(undefined, {
    validators: [Validators.required, Validators.pattern(/^\d{14}$/)],
  });

  /**
   * Constructor sets up reactive error handling for server-side validation.
   *
   * Uses an effect to monitor the assignPackageLoading signal and automatically
   * update the form control's error state when server validation fails for the
   * PackageNumber field. The untracked wrapper prevents infinite loops while
   * allowing the effect to respond to signal changes.
   */
  constructor() {
    effect(() => {
      const status = this.assignPackageLoading();
      untracked(() => {
        if (status?.invalidProperties?.['PackageNumber']) {
          this.control.setErrors({
            invalidProperties: status?.invalidProperties?.['PackageNumber'],
          });
        } else {
          this.control.setErrors(null);
        }
      });
    });
  }

  /**
   * Handles scanned package number input from the scanner component.
   *
   * When a valid value is scanned, it automatically populates the form control.
   * This provides a convenient way for users to input package numbers without
   * manual typing, reducing input errors and improving workflow efficiency.
   *
   * @param value - The scanned package number string
   *
   * @example
   * ```html
   * <isa-scanner-button (scanned)="onScan($event)" />
   * ```
   */
  onScan(value: string): void {
    this.control.setValue(value);
  }

  /**
   * Handles form submission and validation for package number assignment.
   *
   * This method performs comprehensive validation before emitting the result:
   * 1. Checks if a request is currently in progress (prevents double submission)
   * 2. Triggers form validation to ensure package number meets requirements
   * 3. Validates that a value was actually provided and is not null/undefined
   * 4. Emits the appropriate result based on validation outcome
   *
   * If validation fails or no value is provided, emits undefined to indicate
   * the operation should be cancelled or retried. If validation passes,
   * emits the validated package number for processing.
   *
   * @param value - The package number value to validate and process
   *
   * @example
   * ```html
   * <form (ngSubmit)="onSave(control.value)">
   *   <input [formControl]="control" />
   *   <button type="submit" [disabled]="assignPackageLoading().loading">
   *     Assign Package
   *   </button>
   * </form>
   * ```
   *
   * @example
   * ```typescript
   * // In parent component
   * onAssignPackage(packageNumber: string | undefined): void {
   *   if (packageNumber) {
   *     // Process the validated package number
   *     this.remissionService.assignPackage(packageNumber);
   *   } else {
   *     // Handle validation failure or cancellation
   *     this.showError('Please provide a valid 14-digit package number');
   *   }
   * }
   * ```
   */
  onSave(value: string | undefined): void {
    if (this.assignPackageLoading().loading) {
      return;
    }

    this.control.updateValueAndValidity();

    if (
      this.control.invalid ||
      this.control?.value === null ||
      this.control?.value === undefined
    ) {
      return this.assignPackageNumber.emit(undefined);
    }

    return this.assignPackageNumber.emit(value);
  }
}
