import {
  ChangeDetectionStrategy,
  Component,
  signal,
  inject,
} from '@angular/core';

import { DialogContentDirective } from '@isa/ui/dialog';
import { provideIcons } from '@ng-icons/core';
import { isaActionScanner } from '@isa/icons';
import { CreateReturnReceiptComponent } from './create-return-receipt.component';
import { AssignPackageNumberComponent } from './assign-package-number.component';
import {
  CreateRemission,
  RemissionReturnReceiptService,
} from '@isa/remission/data-access';

/**
 * Enumeration of possible return receipt result types.
 * Used to determine the action taken by the user in the return receipt creation step.
 */
export enum ReturnReceiptResultType {
  /** User closed the dialog without action */
  Close = 'close',
  /** User chose to generate a receipt number automatically */
  Generate = 'generate',
  /** User chose to input a custom receipt number */
  Input = 'input',
}

/**
 * Union type representing the possible results from the return receipt creation step.
 * Each variant corresponds to a different user action in the dialog.
 */
export type ReturnReceiptResult =
  | { type: ReturnReceiptResultType.Close }
  | { type: ReturnReceiptResultType.Generate }
  | {
      type: ReturnReceiptResultType.Input;
      /** The custom receipt number entered by the user */
      value: string | undefined | null;
    }
  | undefined;

/**
 * Request status object used to track the state of asynchronous operations.
 * Contains loading state and optional validation error information.
 */
export type RequestStatus = {
  /** Whether the request is currently in progress */
  loading: boolean;
  /** Map of property names to error messages for validation failures */
  invalidProperties?: Record<string, string>;
};

/**
 * Input data required to initialize the remission start dialog.
 */
export type RemissionStartDialogData = {
  /** The return group identifier for the remission process */
  returnGroup: string | undefined;

  /** #5289 - Flag indicating if the dialog is opened for package assignment only */
  assignPackage?:
    | {
        returnId: number;
        receiptId: number;
      }
    | undefined;
};

/**
 * Result data returned when the remission start dialog completes successfully.
 */
export type RemissionStartDialogResult = {
  /** The unique identifier of the created return */
  returnId: number;
  /** The unique identifier of the created receipt */
  receiptId: number;
};

/**
 * Dialog component for initiating the remission process.
 *
 * This component manages a two-step workflow:
 * 1. Create a return receipt (either generate automatically or accept manual input)
 * 2. Assign a package number to the created return
 *
 * The component extends DialogContentDirective to provide dialog functionality
 * and uses Angular signals for reactive state management.
 *
 * @example
 * ```typescript
 * // Opening the dialog
 * const dialogRef = this.dialog.open(RemissionStartDialogComponent, {
 *   data: { returnGroup: 'RG123' }
 * });
 *
 * // Handling the result
 * dialogRef.afterClosed().subscribe(result => {
 *   if (result) {
 *     console.log('Return created:', result.returnId);
 *     console.log('Receipt created:', result.receiptId);
 *   }
 * });
 * ```
 */
@Component({
  selector: 'remi-remission-start-dialog',
  templateUrl: './remission-start-dialog.component.html',
  styleUrl: './remission-start-dialog.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CreateReturnReceiptComponent, AssignPackageNumberComponent],
  providers: [provideIcons({ isaActionScanner })],
})
export class RemissionStartDialogComponent extends DialogContentDirective<
  RemissionStartDialogData,
  RemissionStartDialogResult | undefined
> {
  /** Service for handling remission and return receipt operations */
  #remissionReturnReceiptService = inject(RemissionReturnReceiptService);

  /**
   * Signal tracking the request status for the create remission operation.
   * Used to show loading states and validation errors in the first step.
   */
  createRemissionRequestStatus = signal<RequestStatus>({ loading: false });

  /**
   * Signal tracking the request status for the assign package operation.
   * Used to show loading states and validation errors in the second step.
   */
  assignPackageRequestStatus = signal<RequestStatus>({ loading: false });

  /**
   * Signal containing the data needed for the package assignment step.
   * Set after successful return receipt creation and used in the second step.
   */
  assignPackageStepData = signal<
    Omit<CreateRemission, 'invalidProperties'> | undefined
  >(undefined);

  /**
   * Handles the completion of the return receipt creation step.
   *
   * This method processes the user's choice regarding receipt creation:
   * - If the user closes or cancels, the dialog is closed with no result
   * - If the user chooses to generate or input a receipt, a remission is created
   * - On successful creation, the workflow advances to the package assignment step
   *
   * @param returnReceipt - The result from the return receipt creation step
   * @returns Promise that resolves when the operation completes
   *
   * @example
   * ```typescript
   * // Called from template when user completes first step
   * onCreateReturnReceipt({ type: ReturnReceiptResultType.Generate });
   * onCreateReturnReceipt({
   *   type: ReturnReceiptResultType.Input,
   *   value: 'CUSTOM-123'
   * });
   * ```
   */
  async onCreateReturnReceipt(
    returnReceipt: ReturnReceiptResult,
  ): Promise<void> {
    this.createRemissionRequestStatus.set({ loading: true });

    if (
      !returnReceipt ||
      returnReceipt.type === ReturnReceiptResultType.Close
    ) {
      this.onDialogClose(undefined);
    } else {
      try {
        let receiptNumber: string | undefined = undefined; // undefined -> Wird generiert;
        if (
          returnReceipt.type === ReturnReceiptResultType.Input &&
          returnReceipt.value
        ) {
          receiptNumber = returnReceipt.value;
        }

        const response =
          await this.#remissionReturnReceiptService.createRemission({
            returnGroup: this.data.returnGroup,
            receiptNumber,
          });

        if (!response) {
          return this.onDialogClose(undefined);
        }

        this.assignPackageStepData.set({
          returnId: response.returnId,
          receiptId: response.receiptId,
        });
        this.createRemissionRequestStatus.set({ loading: false });
      } catch (error: any) {
        console.error('Error creating remission:', error);
        if (error?.error?.invalidProperties) {
          this.createRemissionRequestStatus.set({
            loading: false,
            invalidProperties: error?.error?.invalidProperties,
          });
        }
      }
    }
  }

  /**
   * Handles the completion of the package assignment step.
   *
   * This method assigns a package number to the previously created return
   * and completes the remission start workflow. On successful assignment,
   * the dialog closes with the return and receipt IDs.
   *
   * @param packageNumber - The package number to assign to the return
   * @returns Promise that resolves when the operation completes
   *
   * @example
   * ```typescript
   * // Called from template when user completes second step
   * onAssignPackageNumber('PKG-789');
   * ```
   */
  async onAssignPackageNumber(
    packageNumber: string | undefined,
  ): Promise<void> {
    this.assignPackageRequestStatus.set({ loading: true });
    const data = this.assignPackageStepData() ?? this.data?.assignPackage;

    if (!data || !packageNumber) {
      return this.onDialogClose(undefined);
    }

    const returnId = data.returnId;
    const receiptId = data.receiptId;

    try {
      const response = await this.#remissionReturnReceiptService.assignPackage({
        packageNumber,
        returnId,
        receiptId,
      });

      if (!response) {
        return this.onDialogClose(undefined);
      }

      this.onDialogClose({
        returnId,
        receiptId,
      });
      this.assignPackageRequestStatus.set({ loading: false });
    } catch (error: any) {
      console.error('Error assigning package:', error);
      if (error?.error?.invalidProperties) {
        this.assignPackageRequestStatus.set({
          loading: false,
          invalidProperties: error?.error?.invalidProperties,
        });
      }
    }
  }

  /**
   * Closes the dialog with the specified result.
   *
   * This method wraps the inherited close method from DialogContentDirective
   * to provide a consistent interface for closing the dialog from various
   * points in the workflow.
   *
   * @param result - The result to return to the dialog opener, or undefined if cancelled
   *
   * @example
   * ```typescript
   * // Close with successful result
   * this.onDialogClose({ returnId: 123, receiptId: 456 });
   *
   * // Close without result (cancelled)
   * this.onDialogClose(undefined);
   * ```
   */
  onDialogClose(result: RemissionStartDialogResult | undefined): void {
    this.close(result);
  }
}
