import { computed, effect, inject, Injectable, signal, untracked } from '@angular/core';

import { CartService } from '../../../../core/services/cart/cart.service';
import { CheckoutService } from '../../../../core/services/checkout.service';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import { PaymentMethod, PaymentMethodOption, TransferAccount, TransferField } from './checkout-page.models';

@Injectable()
export class CheckoutPaymentFacade {
  private readonly cartService = inject(CartService);
  private readonly checkoutService = inject(CheckoutService);
  private readonly tenantService = inject(TenantService);
  private readonly toastService = inject(ToastService);
  private readonly purchaseId = signal<number | null>(null);
  private readonly isGeneratingIntent = signal(false);

  readonly paymentMethods: ReadonlyArray<PaymentMethodOption> = [
    { id: 'qr', label: 'QR' },
    { id: 'transfer', label: 'Transferencia' },
    { id: 'telepagos', label: 'TelePagos' }
  ];
  readonly selectedMethod = signal<PaymentMethod>('qr');
  readonly copiedTransferField = signal<TransferField | null>(null);
  readonly transferAccount = signal<TransferAccount | null>(null);
  readonly payerDni = signal('');
  readonly transferRequestError = signal<string | null>(null);
  readonly qrData = signal<string | null>(null);
  readonly isLoading = computed(() => this.isGeneratingIntent() || this.cartService.isUpdating());
  readonly canComplete = computed(() =>
    !this.isLoading()
      && (this.selectedMethod() !== 'transfer' || this.transferAccount() !== null)
  );

  constructor() {
    effect(() => {
      const cart = this.cartService.cart();
      const purchaseId = this.purchaseId();

      untracked(() => {
        if (cart && purchaseId) void this.refreshSelectedMethod();
      });
    });
  }

  setPurchaseId(purchaseId: number | null): void {
    this.purchaseId.set(purchaseId);
  }

  async selectMethod(method: PaymentMethod): Promise<void> {
    this.selectedMethod.set(method);
    await this.refreshSelectedMethod();
  }

  async requestTransferData(dni: string): Promise<void> {
    const context = this.resolvePaymentContext();
    if (!context) return;

    this.isGeneratingIntent.set(true);
    this.transferRequestError.set(null);

    try {
      const response = await this.checkoutService.generatePaymentIntent(
        context.tenantCode,
        context.purchaseId,
        'transfer',
        dni
      );
      if (!response.transfer_data) {
        throw new Error('No pudimos obtener los datos de transferencia.');
      }

      this.payerDni.set(dni);
      this.transferAccount.set({
        titular: response.transfer_data.titular,
        entidad: response.transfer_data.entidad,
        cvu: response.transfer_data.cvu,
        alias: response.transfer_data.alias
      });
    } catch (error) {
      const message = this.resolveErrorMessage(
        error,
        'No pudimos obtener los datos de transferencia. Intentá nuevamente.'
      );
      this.transferRequestError.set(message);
      this.toastService.danger(message);
    } finally {
      this.isGeneratingIntent.set(false);
    }
  }

  async copyTransferValue(field: TransferField, value: string): Promise<void> {
    if (!globalThis.navigator?.clipboard?.writeText) return;

    try {
      await globalThis.navigator.clipboard.writeText(value);
      this.copiedTransferField.set(field);

      setTimeout(() => {
        if (this.copiedTransferField() === field) this.copiedTransferField.set(null);
      }, 1800);
    } catch {
      this.copiedTransferField.set(null);
    }
  }

  private async refreshSelectedMethod(): Promise<void> {
    const method = this.selectedMethod();
    if (method === 'transfer') {
      if (this.transferAccount() && this.payerDni()) {
        await this.requestTransferData(this.payerDni());
      }
      return;
    }

    if (method === 'telepagos') return;

    const context = this.resolvePaymentContext();
    if (!context) return;

    this.isGeneratingIntent.set(true);
    try {
      const response = await this.checkoutService.generatePaymentIntent(
        context.tenantCode,
        context.purchaseId,
        method
      );
      if (response.qr_data?.qr_code) this.qrData.set(response.qr_data.qr_code);
    } catch (error) {
      this.toastService.danger(this.resolveErrorMessage(
        error,
        'No pudimos obtener la información de pago. Intentá nuevamente.'
      ));
    } finally {
      this.isGeneratingIntent.set(false);
    }
  }

  private resolvePaymentContext(): { tenantCode: string; purchaseId: number } | null {
    const tenant = this.tenantService.tenant();
    const purchaseId = this.purchaseId();
    return tenant && purchaseId ? { tenantCode: tenant.codigo, purchaseId } : null;
  }

  private resolveErrorMessage(error: unknown, fallback: string): string {
    const backendMessage = (error as { error?: { message?: unknown } } | null)?.error?.message;
    if (typeof backendMessage === 'string') return backendMessage;
    return error instanceof Error ? error.message : fallback;
  }
}
