import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  input,
  OnDestroy,
  output,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import {
  calculateAvailableStock,
  calculateTargetStock,
  getStockToRemit,
  RemissionStore,
  ReturnItem,
  ReturnSuggestion,
  StockInfo,
  UpdateItem,
} from '@isa/remission/data-access';
import {
  ProductInfoComponent,
  ProductShelfMetaInfoComponent,
  ProductStockInfoComponent,
} from '@isa/remission/shared/product';
import { ClientRowImports, ItemRowDataImports } from '@isa/ui/item-rows';
import { Breakpoint, breakpoint } from '@isa/ui/layout';
import { injectRemissionListType } from '../injects/inject-remission-list-type';
import { RemissionListItemSelectComponent } from './remission-list-item-select.component';
import { RemissionListItemActionsComponent } from './remission-list-item-actions.component';
import { NoticeComponent } from '@isa/ui/notice';

/**
 * Component representing a single item in the remission list.
 *
 * Displays product information, stock details, and allows the user to change
 * the remission quantity via a dialog. Handles both `ReturnItem` and
 * `ReturnSuggestion` types, adapting logic based on the current remission list type.
 *
 * @remarks
 * - Uses OnPush change detection for performance.
 * - Relies on signals for local state and computed values.
 * - Follows workspace guidelines for type safety, clean code, and documentation.
 *
 * @see https://context7.com/angular/angular/20.0.0/llms.txt?topic=component
 */
@Component({
  selector: 'remi-feature-remission-list-item',
  templateUrl: './remission-list-item.component.html',
  styleUrl: './remission-list-item.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    FormsModule,
    ProductInfoComponent,
    ProductStockInfoComponent,
    ProductShelfMetaInfoComponent,
    ClientRowImports,
    ItemRowDataImports,
    RemissionListItemSelectComponent,
    RemissionListItemActionsComponent,
    NoticeComponent,
  ],
})
export class RemissionListItemComponent implements OnDestroy {
  /**
   * Store for managing selected remission quantities.
   * @private
   */
  #store = inject(RemissionStore);

  /**
   * Signal providing the current breakpoint state.
   * Used to determine layout orientation and visibility of action buttons.
   */
  desktopBreakpoint = breakpoint([Breakpoint.DesktopL, Breakpoint.DesktopXL]);

  /**
   * Signal providing the current remission list type (Abteilung or Pflicht).
   */
  remissionListType = injectRemissionListType();

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

  /**
   * Stock information for the item.
   */
  stock = input.required<StockInfo>();

  /**
   * InputSignal indicating whether the stock information is currently being fetched.
   * Used to show loading states in the UI.
   * @default false
   *
   */
  stockFetching = input<boolean>(false);

  /**
   * Output event emitter for when the item is deleted or updated.
   * Emits an object containing the in-progress state and the item itself.
   */
  removeOrUpdateItem = output<UpdateItem>();

  /**
   * Optional product group value for display or filtering.
   */
  productGroupValue = input<string>('');

  /**
   * Computes the orientation of the product info based on the mobile breakpoint.
   * If on mobile, uses vertical layout; otherwise, horizontal.
   */
  remiProductInfoOrientation = computed(() => {
    return this.desktopBreakpoint() ? 'horizontal' : 'vertical';
  });

  /**
   * Computes the remaining quantity in stock for the current item.
   */
  remainingQuantityInStock = computed(
    () => this.item()?.remainingQuantityInStock,
  );

  /**
   * Computes whether the item has stock to remit.
   * Returns true if stockToRemit and availableStock are greater than 0.
   * #5269 Added availableStock check
   */
  hasStockToRemit = computed(
    () => this.availableStock() > 0 && this.stockToRemit() > 0,
  );

  /**
   * Computes the available stock for the item using stock and removedFromStock.
   * @returns The calculated available stock.
   */
  availableStock = computed(() =>
    calculateAvailableStock({
      stock: this.stock()?.inStock,
      removedFromStock: this.stock()?.removedFromStock,
    }),
  );

  /**
   * Computes the selected stock quantity to remit for the current item.
   * Uses the store's selected quantity for the item's ID.
   */
  selectedStockToRemit = computed(
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    () => this.#store.selectedQuantity()?.[this.item().id!],
  );

  /**
   * Computes whether the selected quantity equals the stock to remit.
   * This is used to determine if the remission quantity can be changed.
   */
  selectedQuantityDiffersFromStockToRemit = computed(
    () =>
      this.selectedStockToRemit() !== undefined &&
      this.selectedStockToRemit() !== this.stockToRemit(),
  );

  /**
   * Computes the stock to remit based on the remission item and available stock.
   * Uses the getStockToRemit helper function.
   */
  stockToRemit = computed(() =>
    getStockToRemit({
      remissionItem: this.item(),
      remissionListType: this.remissionListType(),
      availableStock: this.availableStock(),
    }),
  );

  /**
   * Computes the target stock after remission.
   * Uses the calculateTargetStock helper function.
   * Takes into account the selected quantity and remaining quantity in stock.
   */
  targetStock = computed(() => {
    if (this.selectedQuantityDiffersFromStockToRemit()) {
      return calculateTargetStock({
        availableStock: this.availableStock(),
        stockToRemit: this.selectedStockToRemit(),
      });
    }

    return calculateTargetStock({
      availableStock: this.availableStock(),
      stockToRemit: this.stockToRemit(),
      remainingQuantityInStock: this.remainingQuantityInStock(),
    });
  });

  /**
   * Computes whether to display the impediment for the item.
   * Displays if the item is a descendant of an enabled impediment or if it has its own impediment.
   */
  displayImpediment = computed(
    () =>
      (this.item() as ReturnItem)?.descendantOf?.enabled ||
      this.item()?.impediment,
  );

  /**
   * Computes the impediment comment and attempts for display.
   * If no impediment comment is provided, defaults to 'Restmenge'.
   * Appends the number of attempts if available.
   */
  impediment = computed(() => {
    const comment = this.item()?.impediment?.comment ?? 'Restmenge';
    const attempts = this.item()?.impediment?.attempts;
    return `${comment}${attempts ? ` (${attempts})` : ''}`;
  });

  /**
   * Cleans up the selected item from the store when the component is destroyed.
   * Removes the item using its ID.
   * @returns void
   */
  ngOnDestroy(): void {
    const itemId = this.item()?.id;
    if (itemId) {
      this.#store.removeItem(itemId);
    }
  }
}
