import {
  ChangeDetectionStrategy,
  Component,
  input,
  inject,
  computed,
  effect,
  output,
} from '@angular/core';
import {
  injectFeedbackDialog,
  injectFeedbackErrorDialog,
} from '@isa/ui/dialog';
import { logger } from '@isa/core/logging';
import {
  CustomerBonRedemptionFacade,
  CustomerBonCheckResource,
  BonRedemptionStore,
} from '@isa/crm/data-access';
import { ResponseArgsError } from '@isa/common/data-access';
import { BonInputFieldComponent } from './components/bon-input-field/bon-input-field.component';
import { BonDetailsDisplayComponent } from './components/bon-details-display/bon-details-display.component';
import { BonRedemptionButtonComponent } from './components/bon-redemption-button/bon-redemption-button.component';

/**
 * Component for redeeming customer receipts (Bon) for loyalty points.
 *
 * Allows users to:
 * 1. Enter a Bon number
 * 2. Validate the Bon exists and is valid
 * 3. View Bon summary (date, total)
 * 4. Redeem the Bon for customer points
 *
 * @example
 * <crm-customer-bon-redemption [cardCode]="activeCardCode()" />
 */
@Component({
  selector: 'crm-customer-bon-redemption',
  imports: [
    BonInputFieldComponent,
    BonDetailsDisplayComponent,
    BonRedemptionButtonComponent,
  ],
  providers: [BonRedemptionStore, CustomerBonCheckResource],
  templateUrl: './crm-feature-customer-bon-redemption.component.html',
  styleUrl: './crm-feature-customer-bon-redemption.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CrmFeatureCustomerBonRedemptionComponent {
  #logger = logger(() => ({
    component: 'CrmFeatureCustomerBonRedemptionComponent',
    cardCode: this.cardCode(),
  }));

  #bonCheckResource = inject(CustomerBonCheckResource);
  #bonFacade = inject(CustomerBonRedemptionFacade);
  #errorFeedbackDialog = injectFeedbackErrorDialog();
  #feedbackDialog = injectFeedbackDialog();

  /**
   * Store for managing Bon redemption state
   */
  readonly store = inject(BonRedemptionStore);

  /**
   * Active loyalty card code for the customer
   */
  readonly cardCode = input<string | undefined>(undefined);

  /**
   * Computed: Disable redemption if no card code
   */
  readonly disableRedemption = computed(
    () => this.store.disableRedemption() || !this.cardCode(),
  );

  readonly redeemed = output<void>();

  /**
   * Constructor - sets up effects to sync resource state with store
   */
  constructor() {
    // Sync resource loading state with store
    effect(() => {
      const isLoading = this.#bonCheckResource.resource.isLoading();
      this.store.setValidating(isLoading);
    });

    // Sync resource results with store
    effect(() => {
      const result = this.#bonCheckResource.resource.hasValue()
        ? this.#bonCheckResource.resource.value()
        : undefined;
      const error = this.#bonCheckResource.resource.error();
      const isLoading = this.#bonCheckResource.resource.isLoading();
      const validationAttempted = this.store.validationAttempted();

      // Only process results if validation was attempted
      if (!validationAttempted || isLoading) {
        return;
      }

      // Handle validation result
      if (result) {
        this.store.setValidatedBon({
          bonNumber: this.store.bonNumber(),
          date: result.date ?? '',
          total: result.total ?? 0,
        });
      }
      // Check if validation returned no result
      else if (!error && !result) {
        this.store.setError('Keine verpunktung möglich');
      }
      // Handle API errors
      else if (error) {
        const errorMsg = this.#extractErrorMessage(error);
        this.store.setError(errorMsg);
      }
    });
  }

  /**
   * Validate the entered Bon number
   */
  validateBon(): void {
    const cardCode = this.cardCode();
    const bonNr = this.store.bonNumber().trim();

    if (!cardCode || !bonNr) {
      this.#logger.warn(
        'Cannot validate Bon: missing required parameters',
        () => ({
          hasCardCode: !!cardCode,
          hasBonNr: !!bonNr,
        }),
      );
      return;
    }

    this.#logger.debug('Triggering Bon validation', () => ({
      cardCode,
      bonNr,
    }));
    this.store.setValidationAttempted(true);
    this.#bonCheckResource.params({ cardCode, bonNr });
  }

  /**
   * Redeem the validated Bon for customer points
   */
  async redeemBon() {
    this.store.setRedeeming(true);

    try {
      const cardCode = this.cardCode();
      const bonNr = this.store.bonNumber().trim();
      const validatedBon = this.store.validatedBon();

      if (!cardCode) {
        throw new Error('Kein Karten-Code vorhanden');
      }

      if (!bonNr || !validatedBon) {
        throw new Error('Bon muss zuerst validiert werden');
      }

      this.#logger.debug('Redeeming Bon', () => ({ cardCode, bonNr }));

      const success = await this.#bonFacade.addBon({ cardCode, bonNr });

      if (!success) {
        throw new Error('Bon-Einlösung fehlgeschlagen');
      }

      this.#logger.info('Bon redeemed successfully', () => ({
        bonNr,
        total: validatedBon.total,
      }));

      this.#feedbackDialog({
        data: {
          message: 'Bon wurde erfolgreich gebucht',
          autoClose: true,
          autoCloseDelay: 10000,
        },
      });

      // Reset form
      this.resetForm();
      this.redeemed.emit();
    } catch (error: unknown) {
      this.#logger.error('Bon redemption failed', error as Error, () => ({
        bonNr: this.store.bonNumber(),
      }));

      let errorMsg = 'Bon-Einlösung fehlgeschlagen';

      if (error instanceof ResponseArgsError) {
        errorMsg = error.message || errorMsg;
      } else if (error instanceof Error) {
        errorMsg = error.message;
      }

      this.#errorFeedbackDialog({
        data: {
          errorMessage: errorMsg,
        },
      });
    } finally {
      this.store.setRedeeming(false);
    }
  }

  /**
   * Reset the form to initial state
   */
  resetForm(): void {
    this.store.reset();
    this.#bonCheckResource.reset();
  }

  /**
   * Extract error message from various error types.
   * ResponseArgsError already formats invalidProperties into a readable message.
   */
  #extractErrorMessage(error: unknown): string {
    const defaultMsg = 'Bon-Validierung fehlgeschlagen';
    const actualError = (error as { cause?: unknown })?.cause ?? error;

    if (actualError instanceof ResponseArgsError) {
      return actualError.message || defaultMsg;
    }

    if (actualError instanceof Error) {
      return actualError.message || defaultMsg;
    }

    return defaultMsg;
  }
}
