import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate, useSearchParams } from 'react-router'
import { Alert, Button, Card, Spinner } from '@/components/ui'
import { usePlatformBrand } from '@/lib/brand'
import { useConfirmCheckout } from '../hooks'

/**
 * Razorpay's `checkout.js` widget, embedded on our own page rather than
 * redirecting to Razorpay's hosted subscription/payment-link page — see
 * `RazorpayPlatformGateway`'s docblock for why (the hosted page is gated by
 * per-account KYC/feature flags and forces a phone+OTP "contact details"
 * capture step that a real customer flow, and Stripe's own equivalent,
 * don't need). Mirrors appshot-studio's `Checkout/Razorpay.tsx`.
 *
 * The `handler` callback firing means Razorpay's own widget saw a successful
 * payment, but a browser is never the authority on whether money moved
 * (CLAUDE.md: "the till can ask and read but never assert") — so it is not
 * trusted directly. Instead it is POSTed straight to confirmCheckout(),
 * which asks Razorpay itself (a signed, server-to-server call) before
 * activating anything — the same instant-confirm pattern the reference
 * codebase's own `PlanList::confirmRazorpayPayment()` uses. The signed webhook
 * (PlatformBillingWebhookController) stays the fallback for whenever this
 * confirmation call itself fails to reach the server.
 */
const CHECKOUT_SCRIPT = 'https://checkout.razorpay.com/v1/checkout.js'

declare global {
  interface Window {
    Razorpay?: new (options: Record<string, unknown>) => { open: () => void; on: (event: string, handler: (...args: unknown[]) => void) => void }
  }
}

function loadScript(): Promise<void> {
  if (window.Razorpay) return Promise.resolve()
  const existing = document.querySelector<HTMLScriptElement>(`script[src="${CHECKOUT_SCRIPT}"]`)
  if (existing) {
    return new Promise((resolve, reject) => {
      existing.addEventListener('load', () => resolve(), { once: true })
      existing.addEventListener('error', () => reject(new Error('checkout.js failed to load')), { once: true })
    })
  }
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = CHECKOUT_SCRIPT
    script.async = true
    script.onload = () => resolve()
    script.onerror = () => reject(new Error('checkout.js failed to load'))
    document.body.appendChild(script)
  })
}

export function RazorpayCheckoutPage() {
  const { t } = useTranslation()
  const platform = usePlatformBrand()
  const navigate = useNavigate()
  const [searchParams] = useSearchParams()
  const [error, setError] = useState<string | null>(null)
  const opened = useRef(false)
  const confirmCheckout = useConfirmCheckout()

  const subscriptionId = searchParams.get('subscription_id')
  const orderId = searchParams.get('order_id')
  const keyId = searchParams.get('key_id')
  const planName = searchParams.get('plan_name') ?? ''
  const email = searchParams.get('email') ?? undefined
  const amount = searchParams.get('amount')
  const currency = searchParams.get('currency') ?? 'INR'

  useEffect(() => {
    // Idempotent open — StrictMode's double-invoke would otherwise pop the modal twice.
    if (opened.current) return
    if (!keyId || (!subscriptionId && !orderId)) {
      setError(t('This checkout link is missing something it needs.'))

      return
    }
    opened.current = true

    loadScript()
      .then(() => {
        if (!window.Razorpay) {
          setError(t('Razorpay checkout failed to load.'))

          return
        }

        const rzp = new window.Razorpay({
          key: keyId,
          ...(subscriptionId ? { subscription_id: subscriptionId } : { order_id: orderId, amount, currency }),
          name: platform.name,
          description: planName,
          prefill: email ? { email } : undefined,
          handler: (response: unknown) => {
            const r = response as { razorpay_payment_id: string; razorpay_order_id?: string; razorpay_subscription_id?: string; razorpay_signature: string }
            confirmCheckout.mutate(
              {
                provider: 'razorpay',
                payment_id: r.razorpay_payment_id,
                order_id: r.razorpay_order_id,
                subscription_id: r.razorpay_subscription_id,
                signature: r.razorpay_signature,
              },
              {
                // Either way — the webhook is the fallback if this call
                // itself could not reach the server; the outcome the
                // shopkeeper actually sees is decided on Plan & billing.
                onSettled: () => navigate('/settings/plan?checkout=success', { replace: true }),
              },
            )
          },
          modal: {
            ondismiss: () => {
              navigate('/settings/plan?checkout=cancelled', { replace: true })
            },
          },
        })

        rzp.on('payment.failed', (...args: unknown[]) => {
          const arg = args[0] as { error?: { description?: string } } | undefined
          setError(arg?.error?.description ?? t('Payment failed. Please try again.'))
        })

        rzp.open()
      })
      .catch((e: Error) => setError(e.message))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return (
    <div className="mx-auto w-full max-w-sm py-24">
      <Card padded={false}>
        <div className="card-b flex flex-col items-center gap-4 text-center">
          {error ? (
            <>
              <Alert tone="danger" title={t('Could not open checkout')} message={error} />
              <Button variant="secondary" onClick={() => navigate('/settings/plan')}>
                {t('Back to Plan & billing')}
              </Button>
            </>
          ) : (
            <>
              <Spinner />
              <p className="text-sm text-content-3">{t('Opening Razorpay checkout…')}</p>
            </>
          )}
        </div>
      </Card>
    </div>
  )
}

export default RazorpayCheckoutPage
