import {
  ChangeDetectionStrategy,
  Component,
  OnDestroy,
  OnInit,
  PLATFORM_ID,
  computed,
  inject,
  signal,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';

import {
  CheckoutService,
  PurchasePaymentVerificationResponse,
  PurchaseStatusResponse,
} from '../../../../core/services/checkout.service';
import { CartService } from '../../../../core/services/cart/cart.service';
import { findMenu } from '../../../../core/services/menu.utils';
import { TenantService } from '../../../../core/services/tenant.service';
import { ButtonComponent } from '../../../../shared/components/button/button.component';

type PurchaseStatusView = 'approved' | 'pending' | 'rejected' | 'expired' | 'error';

const PAYMENT_STATUS_POLL_INTERVAL_MS = 5_000;

@Component({
  selector: 'app-purchase-status-page',
  standalone: true,
  imports: [ButtonComponent],
  templateUrl: './purchase-status-page.component.html',
  styleUrl: './purchase-status-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PurchaseStatusPageComponent implements OnInit, OnDestroy {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly checkoutService = inject(CheckoutService);
  private readonly cartService = inject(CartService);
  private readonly tenantService = inject(TenantService);
  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));

  private purchaseId: string | null = null;
  private tenantCode: string | null = null;
  private pollingTimeout: ReturnType<typeof setTimeout> | null = null;
  private isDestroyed = false;

  protected readonly isLoading = signal(true);
  protected readonly status = signal<PurchaseStatusView>('pending');
  protected readonly hasGeneratedTickets = signal(false);
  protected readonly paymentIssueMessage = signal<string | null>(null);
  protected readonly ticketsRoute = computed(() => {
    if (!this.hasGeneratedTickets()) {
      return null;
    }

    return findMenu(this.tenantService.tenant()?.menues ?? [], 'account.tickets')?.route ?? null;
  });
  protected readonly whatsappUrl = computed(
    () =>
      this.tenantService
        .tenant()
        ?.social_media?.find((socialMedia) => socialMedia.code === 'whatsapp')?.url ?? null,
  );

  ngOnInit(): void {
    const purchaseId = this.route.snapshot.paramMap.get('id');
    const tenant = this.tenantService.tenant();

    if (!purchaseId || !tenant) {
      void this.router.navigate(['/']);
      return;
    }

    this.purchaseId = purchaseId;
    this.tenantCode = tenant.codigo;

    if (this.route.snapshot.queryParamMap?.get('status') === 'expired') {
      this.status.set('expired');
      this.isLoading.set(false);
      return;
    }

    void this.loadStatus();
  }

  ngOnDestroy(): void {
    this.isDestroyed = true;
    this.stopPolling();
  }

  private async loadStatus(isPolling = false): Promise<void> {
    if (!this.purchaseId || !this.tenantCode) {
      return;
    }

    try {
      const purchase = await this.checkoutService
        .withCustomLoading()
        .getPurchase(this.tenantCode, this.purchaseId);

      if (this.isDestroyed) {
        return;
      }

      const status = this.resolveStatus(purchase);
      this.status.set(status);
      this.hasGeneratedTickets.set(purchase.has_generated_tickets === true);
      this.paymentIssueMessage.set(this.resolvePaymentIssueMessage(purchase.payment_verification));

      if (status === 'approved') {
        this.cartService.clearCart();
      }

      if (status === 'pending') {
        this.schedulePolling();
      } else {
        this.stopPolling();
      }
    } catch (error) {
      console.error('Failed to fetch purchase status:', error);

      if (!this.isDestroyed) {
        if (this.isPurchaseExpiredError(error)) {
          this.status.set('expired');
          this.stopPolling();
        } else if (isPolling) {
          this.schedulePolling();
        } else {
          this.status.set('error');
        }
      }
    } finally {
      if (!this.isDestroyed) {
        this.isLoading.set(false);
      }
    }
  }

  private schedulePolling(): void {
    if (!this.isBrowser || this.isDestroyed || this.pollingTimeout) {
      return;
    }

    this.pollingTimeout = setTimeout(() => {
      this.pollingTimeout = null;
      void this.loadStatus(true);
    }, PAYMENT_STATUS_POLL_INTERVAL_MS);
  }

  private stopPolling(): void {
    if (this.pollingTimeout) {
      clearTimeout(this.pollingTimeout);
      this.pollingTimeout = null;
    }
  }

  private resolveStatus(purchase: PurchaseStatusResponse): PurchaseStatusView {
    if (purchase.status === 'paid') {
      return 'approved';
    }

    if (purchase.status === 'rejected' || purchase.status === 'cancelled') {
      return 'rejected';
    }

    if (purchase.status === 'expired') {
      return 'expired';
    }

    return 'pending';
  }

  private resolvePaymentIssueMessage(
    verification?: PurchasePaymentVerificationResponse,
  ): string | null {
    const primary = verification?.primary;

    if (!primary) {
      return null;
    }

    const primaryMessage = (() => {
      switch (primary.reason) {
        case 'ambiguous_exact_match':
          return 'Encontramos una transferencia que también coincide con otra compra.';
        case 'exact_dni_near_amount':
          return `El DNI coincide, pero el monto transferido tiene una diferencia de ${this.formatCurrency(primary.amount_difference)}.`;
        case 'exact_amount_near_dni':
          return primary.dni_distance === null
            ? 'El monto coincide, pero el DNI del pagador es diferente.'
            : `El monto coincide, pero el DNI del pagador presenta ${primary.dni_distance} ${primary.dni_distance === 1 ? 'diferencia' : 'diferencias'} de escritura.`;
      }
    })();

    if (verification.candidate_count > 1) {
      return `Encontramos ${verification.candidate_count} transferencias posibles. ${primaryMessage}`;
    }

    return primaryMessage;
  }

  private formatCurrency(amount: string): string {
    return new Intl.NumberFormat('es-AR', {
      style: 'currency',
      currency: 'ARS',
      maximumFractionDigits: 2,
    }).format(Number(amount));
  }

  private isPurchaseExpiredError(error: unknown): boolean {
    if (typeof error !== 'object' || error === null || !('error' in error)) {
      return false;
    }

    return (error as { error?: { code?: string } }).error?.code === 'purchase.expired';
  }

  protected goToTickets(): void {
    const route = this.ticketsRoute();

    if (route) {
      void this.router.navigateByUrl(route);
    }
  }

  protected openWhatsApp(): void {
    const url = this.whatsappUrl();

    if (url) {
      window.open(url, '_blank', 'noopener,noreferrer');
    }
  }
}
