'use client';
import { Suspense, useEffect, useRef, type ReactNode } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import { useRouter, useSearchParams } from 'next/navigation';
import { useQueryClient } from '@tanstack/react-query';
import { CircularProgress, Paper, Stack, Typography } from '@mui/material';
import { AppButton, AppIcon, AppLoading, PaymentStatusBadge } from '@/components';
import { ROUTES } from '@/constants';
import { useConfirmGatewayReturn, usePaymentOutcome } from '@/services/payment';
import { invalidateAfterPaymentSuccess } from '@/services/payment/invalidations';
import {
  CHECKOUT_QUERY_BOOKING_ID,
  CHECKOUT_QUERY_OUTCOME,
  CHECKOUT_QUERY_REQUEST_ID,
  CHECKOUT_QUERY_TRANSACTION_ID,
} from '@/services/payment/constants';

/**
 * Return-from-gateway surface — drives the tail of the checkout state machine: report the return
 * (`useConfirmGatewayReturn`; the capture trigger in the mock, an outcome read on the real path), then a
 * **pending-callback** state backed by the backoff poll ("PSP received ≠ cash in bank" — pending is
 * normal, reflected calmly) until a terminal outcome: succeeded → invalidate the booking/request caches
 * and hand off to the confirmation screen; failed → a retry affordance (a fresh C6 mount = a new attempt
 * with a NEW idempotency key); window lapsed → back to the request's terminal card.
 */
export default function CheckoutReturnPage() {
  return (
    <Suspense fallback={<AppLoading />}>
      <ReturnScreen />
    </Suspense>
  );
}

function ReturnScreen() {
  const t = useTranslations('payment');
  const locale = useLocale();
  const router = useRouter();
  const params = useSearchParams();
  const queryClient = useQueryClient();

  const requestId = Number(params.get(CHECKOUT_QUERY_REQUEST_ID));
  const validId = Number.isInteger(requestId) && requestId > 0;
  const transactionIdParam = params.get(CHECKOUT_QUERY_TRANSACTION_ID);
  const transactionId = transactionIdParam ? Number(transactionIdParam) : null;
  const gatewayOutcome = params.get(CHECKOUT_QUERY_OUTCOME) === 'failure' ? ('failure' as const) : ('success' as const);

  const confirm = useConfirmGatewayReturn();
  const { mutate: confirmMutate } = confirm;

  // Fire the return report exactly once per mount — a browser refresh on this page replays it, which the
  // backend/mock treat as a duplicate (idempotent convergence, per the webhook-dedup rule).
  const confirmFiredRef = useRef(false);
  useEffect(() => {
    if (confirmFiredRef.current || !validId) return;
    confirmFiredRef.current = true;
    confirmMutate({ bookingRequestId: requestId, transactionId, outcome: gatewayOutcome });
  }, [confirmMutate, validId, requestId, transactionId, gatewayOutcome]);

  // The poll takes over once the return report settles (its result is primed into the outcome key).
  const confirmSettled = confirm.isSuccess || confirm.isError;
  const outcomeQuery = usePaymentOutcome(validId ? requestId : undefined, {
    enabled: confirmSettled,
  });
  // Trust the outcome cache only after THIS mount's report settled — a previous attempt's failed outcome
  // survives in the cache and would otherwise flash a false "payment failed" (with a live retry CTA)
  // while the current attempt's capture is still in flight.
  const outcome = confirmSettled ? outcomeQuery.data : undefined;

  const succeeded = outcome?.transactionStatus === 'succeeded' || outcome?.requestStatus === 'converted';
  const windowExpired = outcome?.requestStatus === 'payment_deadline_expired';
  const failed = !succeeded && !windowExpired && outcome?.transactionStatus === 'failed';

  // Hand off to the confirmation exactly once. The confirm mutation already invalidated on an immediate
  // success; a success that arrived later through the poll invalidates here instead (never twice).
  const navigatedRef = useRef(false);
  const confirmSawSuccess = confirm.data?.transactionStatus === 'succeeded';
  useEffect(() => {
    if (!succeeded || navigatedRef.current || !outcome) return;
    navigatedRef.current = true;
    if (!confirmSawSuccess) {
      invalidateAfterPaymentSuccess(queryClient, outcome.bookingRequestId, outcome.bookingId);
    }
    const query = new URLSearchParams({ [CHECKOUT_QUERY_REQUEST_ID]: String(outcome.bookingRequestId) });
    if (outcome.bookingId != null) query.set(CHECKOUT_QUERY_BOOKING_ID, String(outcome.bookingId));
    router.replace(`/${locale}${ROUTES.CHECKOUT_CONFIRMATION}?${query.toString()}`);
  }, [succeeded, outcome, confirmSawSuccess, queryClient, router, locale]);

  if (!validId) {
    return (
      <StateCard icon="error" tone="var(--bal-error)" title={t('error_title')}>
        <AppButton variant="contained" onClick={() => router.replace(`/${locale}${ROUTES.BOOKINGS}`)}>
          {t('view_booking')}
        </AppButton>
      </StateCard>
    );
  }

  if (windowExpired) {
    return (
      <StateCard icon="pending" tone="var(--bal-warning)" title={t('window_expired_title')} body={t('window_expired_body')}>
        <AppButton
          variant="contained"
          onClick={() => router.replace(`/${locale}${ROUTES.BOOKING_REQUEST_STATUS}/${requestId}`)}
        >
          {t('back_to_request')}
        </AppButton>
      </StateCard>
    );
  }

  if (failed) {
    return (
      <StateCard icon="error" tone="var(--bal-error)" title={t('state_failed_title')} body={t('state_failed_hint')}>
        <PaymentStatusBadge status="failed" />
        <AppButton
          color="secondary"
          variant="contained"
          size="large"
          onClick={() =>
            router.replace(`/${locale}${ROUTES.CHECKOUT}?${CHECKOUT_QUERY_REQUEST_ID}=${requestId}`)
          }
        >
          {t('retry_payment')}
        </AppButton>
        <AppButton
          variant="text"
          onClick={() => router.replace(`/${locale}${ROUTES.BOOKING_REQUEST_STATUS}/${requestId}`)}
        >
          {t('back_to_request')}
        </AppButton>
      </StateCard>
    );
  }

  // Pending-callback (and the brief succeeded → confirmation hand-off): a calm waiting state.
  return (
    <StateCard icon="payment" tone="var(--bal-secondary)" title={t('state_pending_title')} body={t('state_pending_hint')}>
      <CircularProgress color="primary" size="2.5rem" />
      <PaymentStatusBadge status="pending" />
      {/* Manual re-check — covers the bounded poll giving up on a very slow callback. */}
      <AppButton variant="text" disabled={outcomeQuery.isFetching} onClick={() => outcomeQuery.refetch()}>
        {t('check_again')}
      </AppButton>
    </StateCard>
  );
}

function StateCard({
  icon,
  tone,
  title,
  body,
  children,
}: {
  icon: string;
  tone: string;
  title: string;
  body?: string;
  children?: ReactNode;
}) {
  return (
    <Paper elevation={0} sx={{ p: 4, textAlign: 'center', border: '1px solid', borderColor: 'divider', borderRadius: 2 }}>
      <Stack sx={{ gap: 1.5, alignItems: 'center' }}>
        <AppIcon icon={icon} size={44} color={tone} />
        <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
          {title}
        </Typography>
        {body ? (
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {body}
          </Typography>
        ) : null}
        {children}
      </Stack>
    </Paper>
  );
}
