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 { useConfirmCheckout } from '../hooks'

/**
 * PayPal's JS SDK Smart Buttons, embedded on our own page rather than a
 * hosted redirect — same reasoning as `RazorpayCheckoutPage`: the payer is
 * already a browser, the store owner in the SPA, so a popup beats a full
 * navigation away.
 *
 * The `onApprove` callback firing means PayPal's own widget saw the buyer
 * approve, but a browser is never the authority on whether money moved — it
 * is POSTed straight to confirmCheckout(), which asks PayPal itself (a
 * signed, server-to-server call) before activating anything. The signed
 * webhook (PlatformBillingWebhookController) stays the fallback for whenever
 * this confirmation call itself fails to reach the server.
 *
 * An Order (lifetime) was already created server-side, so `createOrder` just
 * hands the SDK the id — nothing about the amount is decided in the browser.
 * A Subscription (monthly/annual) has no id yet: PayPal's own recommended
 * integration creates it client-side against a plan_id that WAS fixed
 * server-side, which is what keeps the price out of the buyer's hands here
 * too.
 */
declare global {
  interface Window {
    paypal?: {
      Buttons: (options: Record<string, unknown>) => { render: (selector: string) => void }
    }
  }
}

function sdkSrc(clientId: string, mode: 'order' | 'subscription'): string {
  const params = new URLSearchParams({ 'client-id': clientId, intent: mode === 'subscription' ? 'subscription' : 'capture' })
  if (mode === 'subscription') params.set('vault', 'true')

  return `https://www.paypal.com/sdk/js?${params.toString()}`
}

function loadScript(src: string): Promise<void> {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = src
    script.async = true
    script.onload = () => resolve()
    script.onerror = () => reject(new Error('PayPal checkout failed to load'))
    document.body.appendChild(script)
  })
}

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

  const clientId = searchParams.get('client_id')
  const orderId = searchParams.get('order_id')
  const planId = searchParams.get('plan_id')
  const customId = searchParams.get('custom_id')

  useEffect(() => {
    // Idempotent render — StrictMode's double-invoke would otherwise render
    // the button twice into the same container.
    if (rendered.current) return
    if (!clientId || (!orderId && !planId)) {
      setError(t('This checkout link is missing something it needs.'))

      return
    }
    rendered.current = true

    const mode: 'order' | 'subscription' = orderId ? 'order' : 'subscription'

    loadScript(sdkSrc(clientId, mode))
      .then(() => {
        if (!window.paypal) {
          setError(t('PayPal checkout failed to load.'))

          return
        }

        window.paypal
          .Buttons({
            ...(mode === 'order'
              ? { createOrder: () => Promise.resolve(orderId) }
              : {
                  createSubscription: (_data: unknown, actions: { subscription: { create: (input: Record<string, unknown>) => Promise<string> } }) =>
                    actions.subscription.create({ plan_id: planId, custom_id: customId ?? undefined }),
                }),
            onApprove: (data: unknown) => {
              const r = data as { orderID?: string; subscriptionID?: string }
              confirmCheckout.mutate(
                { provider: 'paypal', order_id: r.orderID, subscription_id: r.subscriptionID },
                {
                  // 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 }),
                },
              )
            },
            onCancel: () => {
              navigate('/settings/plan?checkout=cancelled', { replace: true })
            },
            onError: (err: unknown) => {
              setError(err instanceof Error ? err.message : t('Payment failed. Please try again.'))
            },
          })
          .render('#paypal-buttons')
      })
      .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 PayPal checkout…')}</p>
              <div id="paypal-buttons" className="w-full" />
            </>
          )}
        </div>
      </Card>
    </div>
  )
}

export default PaypalCheckoutPage
