import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  input,
  model,
  signal,
} from '@angular/core';
import { FormsModule, Validators } from '@angular/forms';
import { logger } from '@isa/core/logging';
import {
  RemissionItem,
  RemissionItemSource,
  RemissionListType,
  RemissionReturnReceiptService,
  RemissionStore,
  UpdateItem,
} from '@isa/remission/data-access';
import { TextButtonComponent } from '@isa/ui/buttons';
import { injectFeedbackDialog, injectNumberInputDialog } from '@isa/ui/dialog';
import { firstValueFrom } from 'rxjs';
import { injectRemissionListType } from '../injects/inject-remission-list-type';

@Component({
  selector: 'remi-feature-remission-list-item-actions',
  templateUrl: './remission-list-item-actions.component.html',
  styleUrl: './remission-list-item-actions.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [FormsModule, TextButtonComponent],
})
export class RemissionListItemActionsComponent {
  /**
   * Dialog service for prompting the user to enter a remission quantity.
   * @private
   */
  #dialog = injectNumberInputDialog();

  /**
   * Dialog service for providing feedback to the user.
   * @private
   */
  #feedbackDialog = injectFeedbackDialog();

  /**
   * Logger instance for logging component events and errors.
   * @private
   */
  #logger = logger(() => ({
    component: 'RemissionListItemActionsComponent',
  }));

  /**
   * Store for managing selected remission quantities.
   * @private
   */
  #store = inject(RemissionStore);

  /**
   * Signal indicating whether remission has started.
   * Used to determine if the item can be selected or not.
   */
  remissionListType = injectRemissionListType();

  /**
   * Service for handling remission return receipts.
   * @private
   */
  #remissionReturnReceiptService = inject(RemissionReturnReceiptService);

  /**
   * The item to display in the list.
   * Can be either a ReturnItem or a ReturnSuggestion.
   */
  item = input.required<RemissionItem>();

  /**
   * The stock to remit for the current item.
   * This is used to determine if the remission quantity can be changed.
   * @default 0
   */
  stockToRemit = input.required<number>();

  /**
   * Model to track if a delete operation is in progress.
   * And the item being deleted or updated.
   */
  removeOrUpdateItem = model<UpdateItem>({
    inProgress: false,
  });

  /**
   * Signal indicating whether remission has started.
   * Used to determine if the item can be selected or not.
   */
  remissionStarted = computed(() => this.#store.remissionStarted());

  /**
   * Input signal indicating whether the selected quantity differs from the stock to remit.
   * This is used to determine if the remission quantity can be changed.
   */
  selectedQuantityDiffersFromStockToRemit = input<boolean>(true);

  /**
   * Computes whether to display the button for changing remission quantity.
   * Only displays if remission has started and there is stock to remit.
   */
  displayChangeQuantityButton = computed(
    () => this.remissionStarted() && this.stockToRemit() > 0,
  );

  /**
   * Computes whether to display the button for removing manually added items.
   * Only displays if the item's source is 'manually-added'.
   */
  displayRemoveManuallyAddedItemButton = computed(
    () => this.item()?.source === RemissionItemSource.ManuallyAdded,
  );

  /**
   * Signal to highlight the change remission quantity button when dialog is open.
   * Used to improve accessibility and focus management.
   */
  highlight = signal(false);

  /**
   * Opens a dialog to change the remission quantity for the current item.
   * Prompts the user to enter a new quantity and updates the store with the new value
   * if valid.
   * If the item is not found, it updates the impediment with a comment.
   */
  async openRemissionQuantityDialog(): Promise<void> {
    this.highlight.set(true);
    const dialogRef = this.#dialog({
      title: 'Remi-Menge ändern',
      displayClose: true,
      data: {
        message: 'Wie viele Exemplare können remittiert werden?',
        subMessage: this.selectedQuantityDiffersFromStockToRemit()
          ? 'Originale Remi-Menge:'
          : undefined,
        subMessageValue: this.selectedQuantityDiffersFromStockToRemit()
          ? `${this.stockToRemit()}x`
          : undefined,
        inputLabel: 'Remi-Menge',
        closeText: 'Produkt nicht gefunden',
        inputValidation: [
          {
            errorKey: 'required',
            inputValidator: Validators.required,
            errorText: 'Bitte geben Sie eine Menge an.',
          },
          {
            errorKey: 'pattern',
            inputValidator: Validators.pattern(/^[1-9][0-9]*$/),
            errorText: 'Die Menge muss mindestens 1 sein.',
          },
        ],
      },
    });

    const result = await firstValueFrom(dialogRef.closed);
    this.highlight.set(false);

    // Dialog Close
    if (!result) {
      return;
    }

    const itemId = this.item()?.id;
    const quantity = result?.inputValue;

    if (itemId && quantity !== undefined && quantity > 0) {
      // Speichern CTA
      this.#store.updateRemissionQuantity(itemId, this.item(), quantity);
      this.#feedbackDialog({
        data: { message: 'Remi-Menge wurde geändert' },
      });
    } else if (itemId) {
      // Produkt nicht gefunden CTA
      try {
        this.removeOrUpdateItem.set({ inProgress: true });

        let itemToUpdate: RemissionItem | undefined;
        if (this.remissionListType() === RemissionListType.Pflicht) {
          itemToUpdate =
            await this.#remissionReturnReceiptService.updateReturnItemImpediment(
              {
                itemId,
                comment: 'Produkt nicht gefunden',
              },
            );
        }

        if (this.remissionListType() === RemissionListType.Abteilung) {
          itemToUpdate =
            await this.#remissionReturnReceiptService.updateReturnSuggestionImpediment(
              {
                itemId,
                comment: 'Produkt nicht gefunden',
              },
            );
        }
        this.removeOrUpdateItem.set({
          inProgress: false,
          itemId,
          impediment: itemToUpdate?.impediment,
        });
      } catch (error) {
        this.#logger.error('Failed to update impediment', error);
        this.removeOrUpdateItem.set({ inProgress: false });
      }
    }
  }

  /**
   * Deletes the current item from the remission list.
   * Only proceeds if the item has an ID and no other deletion is in progress.
   * Calls the service to delete the item and handles any errors.
   */
  async deleteItemFromList() {
    const itemId = this.item()?.id;
    if (!itemId || this.removeOrUpdateItem().inProgress) {
      return;
    }
    this.removeOrUpdateItem.set({ inProgress: true });

    try {
      await this.#remissionReturnReceiptService.deleteReturnItem({ itemId });
      this.removeOrUpdateItem.set({ inProgress: false, itemId });
    } catch (error) {
      this.#logger.error('Failed to delete return item', error);
      this.removeOrUpdateItem.set({ inProgress: false });
    }
  }
}
