import { useEffect, useMemo, useState, useCallback } from 'react'
import QRCode from 'react-qr-code'
import type { AlbyInvoice } from '@/types/alby'
import { getAlbyService, isWebLNAvailable } from '@/lib/alby'
import { AlbyInstaller } from './AlbyInstaller'
import { Modal, Button } from './ui'
import { t } from '@/lib/i18n'

interface PaymentModalProps {
  invoice: AlbyInvoice
  onClose: () => void
  onPaymentComplete: () => void
}

function useInvoiceTimer(expiresAt?: number): number | null {
  const [timeRemaining, setTimeRemaining] = useState<number | null>(null)

  useEffect(() => {
    if (!expiresAt) {
      return
    }
    const updateTimeRemaining = (): void => {
      const now = Math.floor(Date.now() / 1000)
      const remaining = expiresAt - now
      setTimeRemaining(remaining > 0 ? remaining : 0)
    }
    updateTimeRemaining()
    const interval = setInterval(updateTimeRemaining, 1000)
    return () => clearInterval(interval)
  }, [expiresAt])

  return timeRemaining
}

function PaymentHeader({
  amount,
  timeRemaining,
}: {
  amount: number
  timeRemaining: number | null
}): React.ReactElement {
  const timeLabel = useMemo((): string | null => {
    if (timeRemaining === null) {
      return null
    }
    if (timeRemaining <= 0) {
      return t('payment.expired')
    }
    const minutes = Math.floor(timeRemaining / 60)
    const secs = timeRemaining % 60
    return `${minutes}:${secs.toString().padStart(2, '0')}`
  }, [timeRemaining])

  return (
    <div className="mb-4">
      <h2 className="text-xl font-bold text-neon-cyan">{t('payment.modal.zapAmount', { amount })}</h2>
      {timeLabel && (
        <p className={`text-sm ${timeRemaining !== null && timeRemaining <= 60 ? 'text-red-400 font-semibold' : 'text-cyber-accent/70'}`}>
          {t('payment.modal.timeRemaining', { time: timeLabel })}
        </p>
      )}
    </div>
  )
}

function InvoiceDisplay({ invoiceText, paymentUrl }: { invoiceText: string; paymentUrl: string }): React.ReactElement {
  return (
    <div className="mb-4">
      <p className="text-sm text-cyber-accent mb-2">{t('payment.modal.lightningInvoice')}</p>
      <div className="bg-cyber-darker border border-neon-cyan/20 p-3 rounded break-all text-sm font-mono mb-4 text-neon-cyan">{invoiceText}</div>
      <div className="flex justify-center mb-4">
        <div className="bg-cyber-dark p-4 rounded-lg border-2 border-neon-cyan/30">
          <QRCode
            value={paymentUrl}
            size={200}
            style={{ height: 'auto', maxWidth: '100%', width: '100%' }}
            viewBox="0 0 256 256"
          />
        </div>
      </div>
      <p className="text-xs text-cyber-accent/70 text-center mb-2">{t('payment.modal.scanQr')}</p>
    </div>
  )
}

function PaymentActions({
  copied,
  onCopy,
  onOpenWallet,
}: {
  copied: boolean
  onCopy: () => Promise<void>
  onOpenWallet: () => void
}): React.ReactElement {
  return (
    <div className="flex gap-2">
      <Button
        variant="secondary"
        onClick={() => {
          void onCopy()
        }}
        className="flex-1"
      >
        {copied ? t('payment.modal.copied') : t('payment.modal.copyInvoice')}
      </Button>
      <Button
        variant="primary"
        onClick={onOpenWallet}
        className="flex-1"
      >
        {t('payment.modal.payWithAlby')}
      </Button>
    </div>
  )
}

function ExpiredNotice({ show }: { show: boolean }): React.ReactElement | null {
  if (!show) {
    return null
  }
  return (
    <div className="mt-4 p-3 bg-red-900/20 border border-red-400/50 rounded-lg">
      <p className="text-sm text-red-400 font-semibold mb-2">{t('payment.modal.invoiceExpired')}</p>
      <p className="text-xs text-red-400/80">{t('payment.modal.invoiceExpiredHelp')}</p>
    </div>
  )
}

type PaymentModalState = {
  copied: boolean
  errorMessage: string | null
  paymentUrl: string
  timeRemaining: number | null
  handleCopy: () => Promise<void>
  handleOpenWallet: () => Promise<void>
}

function usePaymentModalState(invoice: AlbyInvoice, onPaymentComplete: () => void): PaymentModalState {
  const [copied, setCopied] = useState(false)
  const [errorMessage, setErrorMessage] = useState<string | null>(null)
  const paymentUrl = `lightning:${invoice.invoice}`
  const timeRemaining = useInvoiceTimer(invoice.expiresAt)

  const handleCopy = useCallback(
    (): Promise<void> => copyInvoiceToClipboard({ invoice: invoice.invoice, setCopied, setErrorMessage }),
    [invoice.invoice]
  )

  const handleOpenWallet = useCallback(
    (): Promise<void> => openWalletForInvoice({ invoice: invoice.invoice, onPaymentComplete, setErrorMessage }),
    [invoice.invoice, onPaymentComplete]
  )

  return { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet }
}

async function copyInvoiceToClipboard(params: {
  invoice: string
  setCopied: (value: boolean) => void
  setErrorMessage: (value: string | null) => void
}): Promise<void> {
  try {
    await navigator.clipboard.writeText(params.invoice)
    params.setCopied(true)
    scheduleCopiedReset(params.setCopied)
  } catch (e) {
    console.error('Failed to copy:', e)
    params.setErrorMessage(t('payment.modal.copyFailed'))
  }
}

async function openWalletForInvoice(params: {
  invoice: string
  onPaymentComplete: () => void
  setErrorMessage: (value: string | null) => void
}): Promise<void> {
  try {
    await payWithWebLN(params.invoice)
    params.onPaymentComplete()
  } catch (e) {
    const error = normalizePaymentError(e)
    if (isUserCancellationError(error)) {
      return
    }
    console.error('Payment failed:', error)
    params.setErrorMessage(error.message)
  }
}

function normalizePaymentError(error: unknown): Error {
  return error instanceof Error ? error : new Error(String(error))
}

function scheduleCopiedReset(setCopied: (value: boolean) => void): void {
  setTimeout(() => setCopied(false), 2000)
}

function isUserCancellationError(error: Error): boolean {
  return error.message.includes('user rejected') || error.message.includes('cancelled')
}

async function payWithWebLN(invoice: string): Promise<void> {
  const alby = getAlbyService()
  if (!isWebLNAvailable()) {
    throw new Error(t('payment.modal.weblnNotAvailable'))
  }
  await alby.enable()
  await alby.sendPayment(invoice)
}

export function PaymentModal({ invoice, onClose, onPaymentComplete }: PaymentModalProps): React.ReactElement {
  const { copied, errorMessage, paymentUrl, timeRemaining, handleCopy, handleOpenWallet } =
    usePaymentModalState(invoice, onPaymentComplete)
  const handleOpenWalletSync = (): void => {
    void handleOpenWallet()
  }

  return (
    <Modal
      isOpen
      onClose={onClose}
      title={t('payment.modal.zapAmount', { amount: invoice.amount })}
      size="small"
      aria-label={t('payment.modal.zapAmount', { amount: invoice.amount })}
    >
      <AlbyInstaller />
      <PaymentHeader amount={invoice.amount} timeRemaining={timeRemaining} />
      <InvoiceDisplay invoiceText={invoice.invoice} paymentUrl={paymentUrl} />
      <PaymentActions
        copied={copied}
        onCopy={handleCopy}
        onOpenWallet={handleOpenWalletSync}
      />
      <ExpiredNotice show={timeRemaining !== null && timeRemaining <= 0} />
      {errorMessage && (
        <p className="text-xs text-red-400 mt-3 text-center" role="alert">
          {errorMessage}
        </p>
      )}
      <p className="text-xs text-cyber-accent/70 mt-4 text-center">
        {t('payment.modal.autoVerify')}
      </p>
    </Modal>
  )
}
