'use client';

import { useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { bookingApi } from '@/lib/api';
import { useBookingDraft } from '@/lib/store/booking-draft';
import { reportObservability } from '@/hooks/useObservability';

function Spinner() {
  return (
    <svg
      className="h-8 w-8 animate-spin text-primary-600"
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 24 24"
      aria-hidden="true"
    >
      <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
      <path
        className="opacity-75"
        fill="currentColor"
        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
      />
    </svg>
  );
}

const POLL_INTERVAL_MS = 5000;

type PaymobIframeFrameProps = {
  bookingPublicId: string;
  locale: string;
  redirectUrl: string;
  /** Callback invoked when the user opts to cancel and return to summary. */
  onCancel: () => void;
};

/**
 * Feature 054 (US5, T050) — Extracted Paymob frame.
 *
 * Owns the iframe + the 5s payment-status poll. Adds three things the prior
 * inline implementation lacked:
 *  1. A "Cancel & return to summary" link below the iframe (FR-EXT-219).
 *  2. A live "Waiting for confirmation…" heartbeat with `aria-live="polite"`.
 *  3. Captured-but-unconfirmed detection — once `payment_status === 'captured'`
 *     the cancel button is disabled and the heartbeat switches to a verifying
 *     state so the customer cannot abandon mid-settlement.
 *
 * Cancel rotates the booking-draft `paymentIdempotencyKey` so the next attempt
 * generates a fresh key (FR-EXT-220) and the post-message listener is torn
 * down before navigation to avoid stale handlers.
 */
export function PaymobIframeFrame({ bookingPublicId, locale, redirectUrl, onCancel }: PaymobIframeFrameProps) {
  const t = useTranslations('checkout');
  const router = useRouter();
  const resetIdempotencyKey = useBookingDraft((s) => s.resetPaymentIdempotencyKey);

  const [iframeLoaded, setIframeLoaded] = useState(false);
  const [paymentCaptured, setPaymentCaptured] = useState(false);
  const [tick, setTick] = useState(0);
  const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const stopPolling = () => {
    if (pollTimerRef.current) {
      clearInterval(pollTimerRef.current);
      pollTimerRef.current = null;
    }
  };

  // postMessage listener for Paymob success signal.
  useEffect(() => {
    const handler = (event: MessageEvent) => {
      const data = event.data;
      if (
        typeof data === 'object' &&
        data !== null &&
        'paymob_status' in data &&
        (data as { paymob_status?: string }).paymob_status === 'success'
      ) {
        stopPolling();
        router.push(`/${locale}/checkout/confirmed/${bookingPublicId}`);
      }
    };
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, [locale, bookingPublicId, router]);

  // Polling fallback. Watches both lifecycle_status (final confirm) and
  // payment_status (captured-but-unconfirmed — disables cancel).
  useEffect(() => {
    pollTimerRef.current = setInterval(async () => {
      setTick((n) => n + 1);
      try {
        const b = await bookingApi.show(locale, bookingPublicId);
        if (b.lifecycle_status === 'confirmed') {
          stopPolling();
          router.push(`/${locale}/checkout/confirmed/${bookingPublicId}`);
          return;
        }
        if (b.payment_status === 'captured' && !paymentCaptured) {
          setPaymentCaptured(true);
        }
      } catch (err) {
        reportObservability('payment.poll.failed', {
          bookingPublicId,
          error: err instanceof Error ? err.message : String(err),
        });
      }
    }, POLL_INTERVAL_MS);
    return stopPolling;
  }, [locale, bookingPublicId, router, paymentCaptured]);

  const handleCancel = () => {
    if (paymentCaptured) return;
    stopPolling();
    resetIdempotencyKey();
    onCancel();
  };

  return (
    <div className="mt-6">
      <div className="relative overflow-hidden rounded-lg border border-neutral-200 bg-white">
        {!iframeLoaded && (
          <div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-white">
            <Spinner />
            <span className="sr-only">{t('pay.loading_payment')}</span>
            <p className="text-sm text-neutral-500" aria-hidden="true">{t('pay.loading_payment')}</p>
          </div>
        )}
        <iframe
          src={redirectUrl}
          title="Paymob"
          className="min-h-[500px] h-[80svh] max-h-[800px] w-full"
          onLoad={() => setIframeLoaded(true)}
          data-testid="paymob-iframe"
        />
      </div>

      <div className="mt-4 flex items-center justify-between gap-3" data-testid="paymob-heartbeat">
        <p
          role="status"
          aria-live="polite"
          aria-atomic="true"
          className="flex items-center gap-2 text-sm text-neutral-700"
        >
          <span className="relative flex h-2.5 w-2.5">
            <span
              aria-hidden="true"
              className="absolute inline-flex h-full w-full animate-ping rounded-full bg-primary-400 opacity-75"
            />
            <span
              aria-hidden="true"
              className="relative inline-flex h-2.5 w-2.5 rounded-full bg-primary-600"
            />
          </span>
          {paymentCaptured ? t('heartbeat.verifying') : t('heartbeat.waiting')}
          <span className="sr-only" aria-hidden="false">
            {' '}
            ({t('heartbeat.tick', { n: tick })})
          </span>
        </p>

        <button
          type="button"
          onClick={handleCancel}
          disabled={paymentCaptured}
          className="text-sm font-medium text-primary-600 underline-offset-2 hover:underline disabled:cursor-not-allowed disabled:text-neutral-400 disabled:no-underline"
          data-testid="paymob-cancel"
          title={paymentCaptured ? t('cancel.disabled_capturing') : undefined}
        >
          {paymentCaptured ? t('cancel.disabled_capturing') : t('cancel.button')}
        </button>
      </div>
    </div>
  );
}
