import { Button } from '../../../components/ui/button'
import { usePaymentNavigation } from '../lib/navigation'
import React from 'react'
import { PaymentInstructions } from './PaymentInstructions'
import { BcaInstructionList } from './BcaInstructionList'
import { type BankKey } from './PaymentLogos'
import { postCharge } from '../../../services/api'
import { Alert } from '../../../components/alert/Alert'
import { InlinePaymentStatus } from './InlinePaymentStatus'
import { toast } from '../../../components/ui/toast'
import { LoadingOverlay } from '../../../components/LoadingOverlay'
import { getErrorRecoveryAction, mapErrorToUserMessage } from '../../../lib/errorMessages'

// Global guard to prevent duplicate auto-charge across StrictMode double-mounts
const attemptedChargeKeys = new Set<string>()
// Share in-flight charge promises across mounts to avoid losing state on StrictMode remounts
const chargeTasks = new Map<string, Promise<any>>()

export function BankTransferPanel({ orderId, amount, locked, onChargeInitiated, defaultBank }: { orderId: string; amount: number; locked?: boolean; onChargeInitiated?: () => void; defaultBank?: BankKey }) {
  const nav = usePaymentNavigation()
  const [selected] = React.useState<BankKey | null>(defaultBank ?? null)
  const [showGuide, setShowGuide] = React.useState(false)
  const [busy, setBusy] = React.useState(false)
  const [vaCode, setVaCode] = React.useState('')
  const [billKey, setBillKey] = React.useState('')
  const [billerCode, setBillerCode] = React.useState('')
  const [errorMessage, setErrorMessage] = React.useState('')
  const [recovery, setRecovery] = React.useState<'retry' | 'view-existing' | 'back'>('retry')
  const lastChargeKeyRef = React.useRef<string>('')
  const chargingKeyRef = React.useRef<string>('')

  function copy(text: string, label: string) {
    if (!text) return
    navigator.clipboard?.writeText(text)
    toast.success(`${label} disalin: ${text}`)
  }
  // Auto-create VA immediately when a bank is selected (runs once per selection)
  React.useEffect(() => {
    let cancelled = false
    async function run() {
      if (!selected || locked) return
      const chargeKey = `${orderId}:${selected}`
      // If a charge for this key is already in-flight (StrictMode remount), await the shared promise
      if (attemptedChargeKeys.has(chargeKey) && chargeTasks.has(chargeKey)) {
        setErrorMessage('')
        setBusy(true)
        chargingKeyRef.current = chargeKey
        try {
          const res = await chargeTasks.get(chargeKey)!
          // Extract VA / bill info from response
          let va = ''
          if (Array.isArray(res?.va_numbers) && res.va_numbers.length) {
            const match = res.va_numbers.find((v: any) => v?.bank?.toLowerCase() === selected) || res.va_numbers[0]
            va = match?.va_number || ''
          }
          if (!va && typeof res?.permata_va_number === 'string') {
            va = res.permata_va_number
          }
          if (!cancelled) {
            setVaCode(va)
            if (typeof res?.bill_key === 'string') setBillKey(res.bill_key)
            if (typeof res?.biller_code === 'string') setBillerCode(res.biller_code)
            lastChargeKeyRef.current = chargeKey
            if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
            onChargeInitiated?.()
          }
        } catch (e) {
          const msg = mapErrorToUserMessage(e)
          const act = getErrorRecoveryAction(e)
          if (!cancelled) {
            setErrorMessage(msg)
            setRecovery(act)
          }
        } finally {
          if (!cancelled) {
            setBusy(false)
            if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
          }
          // Cleanup shared task once finished
          chargeTasks.delete(chargeKey)
        }
        return
      }
      if (lastChargeKeyRef.current === chargeKey || chargingKeyRef.current === chargeKey) return
      setErrorMessage('')
      setBusy(true)
      chargingKeyRef.current = chargeKey
      attemptedChargeKeys.add(chargeKey)
      try {
        const payload: Record<string, any> = {
          payment_type: 'bank_transfer',
          transaction_details: { order_id: orderId, gross_amount: amount },
          bank_transfer: { bank: selected },
        }
        // Share this in-flight request so remounts can await the same promise
        const task = postCharge(payload)
        chargeTasks.set(chargeKey, task)
        const res = await task
        // Extract VA / bill info from response
        let va = ''
        if (Array.isArray(res?.va_numbers) && res.va_numbers.length) {
          const match = res.va_numbers.find((v: any) => v?.bank?.toLowerCase() === selected) || res.va_numbers[0]
          va = match?.va_number || ''
        }
        if (!va && typeof res?.permata_va_number === 'string') {
          va = res.permata_va_number
        }
        if (!cancelled) {
          setVaCode(va)
          if (typeof res?.bill_key === 'string') setBillKey(res.bill_key)
          if (typeof res?.biller_code === 'string') setBillerCode(res.biller_code)
          lastChargeKeyRef.current = chargeKey
          if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
          onChargeInitiated?.()
        }
      } catch (e) {
        const msg = mapErrorToUserMessage(e)
        const act = getErrorRecoveryAction(e)
        if (!cancelled) {
          setErrorMessage(msg)
          setRecovery(act)
          attemptedChargeKeys.delete(chargeKey)
        }
      } finally {
        if (!cancelled) {
          setBusy(false)
          if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
        }
        // Cleanup shared task once finished
        chargeTasks.delete(chargeKey)
      }
    }
    run()
    return () => { cancelled = true }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selected])

  // Auto-show instructions when BCA is selected to reduce confusion
  React.useEffect(() => {
    if (selected === 'bca' && !showGuide) {
      setShowGuide(true)
    }
  }, [selected])

  return (
    <>
      <LoadingOverlay isLoading={busy} message="Sedang membuat kode pembayaran..." />
      <div className="space-y-3">
        <div className="font-medium">Transfer Bank</div>
        {selected && (
          <div className="flex items-center gap-2 text-base">
            <span className="text-black/60">Bank:</span>
            <span className="text-black/80 font-semibold">{selected.toUpperCase()}</span>
          </div>
        )}
        <div className="text-sm text-black/70">VA dibuat otomatis sesuai bank pilihan Anda.</div>
        {errorMessage && (
          <Alert title="Gagal membuat VA">
            {errorMessage}
            {recovery === 'view-existing' && (
              <div className="mt-2">
                <Button size="sm" onClick={() => nav.toStatus(orderId, 'bank_transfer')}>Lihat Kode Pembayaran</Button>
              </div>
            )}
          </Alert>
        )}
        {selected && (
          <div className="pt-1">
            <div className="rounded-lg p-3 border-2 border-black/30">
              <div className="text-sm font-medium mb-2">Virtual Account</div>
              <div className="text-sm text-black/70">
                {vaCode ? (
                  <span>
                    Nomor VA:
                    <span className="block break-all mt-1 font-mono text-xl sm:text-2xl md:text-3xl font-semibold tracking-normal text-black">{vaCode}</span>
                  </span>
                ) : (
                  <span className="inline-flex items-center gap-2" role="status" aria-live="polite">
                    {busy && <span className="h-3 w-3 animate-spin rounded-full border-2 border-black/40  border-t-transparent" aria-hidden />}
                    {busy ? 'Membuat VA…' : 'VA akan muncul otomatis setelah transaksi dibuat.'}
                  </span>
                )}
                {billKey && (
                  <span className="ml-3">Bill Key: <span className="font-mono text-lg font-semibold text-black">{billKey}</span></span>
                )}
                {billerCode && (
                  <span className="ml-3">Biller Code: <span className="font-mono text-lg font-semibold text-black">{billerCode}</span></span>
                )}
              </div>
              <div className="mt-2 flex gap-2">
                <Button variant="secondary" size="sm" onClick={() => copy(vaCode, 'VA')} disabled={!vaCode}>Copy VA</Button>
                <Button variant="secondary" size="sm" onClick={() => copy(billKey, 'Bill Key')} disabled={!billKey}>Copy Bill Key</Button>
              </div>
            </div>
          </div>
        )}
        {/* Status inline dengan polling otomatis */}
        {selected && (
          <InlinePaymentStatus orderId={orderId} method="bank_transfer" compact />
        )}
        {selected && (
          <div className="pt-2">
            {selected === 'bca' ? (
              <BcaInstructionList />
            ) : (
              <div className="rounded-lg border-2 border-black/30 p-3 bg-white">
                <div className="text-sm font-medium mb-2">Instruksi pembayaran</div>
                <PaymentInstructions method="bank_transfer" />
              </div>
            )}
          </div>
        )}
        {locked && (
          <div className="text-xs text-black/60">Metode terkunci. Gunakan kode VA/bill key untuk menyelesaikan pembayaran.</div>
        )}
        <div className="pt-2 space-y-2">
          {(!vaCode || errorMessage) && (
            <Button
              aria-busy={busy}
              disabled={!selected || busy}
              onClick={async () => {
                try {
                  setErrorMessage('')
                  if (!selected) return
                  const chargeKey = `${orderId}:${selected}`
                  // Guard duplicate charges BEFORE setting busy to avoid stuck loading state
                  if (lastChargeKeyRef.current === chargeKey || chargingKeyRef.current === chargeKey) return
                  // If a charge is already in-flight, await it instead of starting a new one
                  if (attemptedChargeKeys.has(chargeKey) && chargeTasks.has(chargeKey)) {
                    setBusy(true)
                    chargingKeyRef.current = chargeKey
                    try {
                      const res = await chargeTasks.get(chargeKey)!
                      let va = ''
                      if (Array.isArray(res?.va_numbers) && res.va_numbers.length) {
                        const match = res.va_numbers.find((v: any) => v?.bank?.toLowerCase() === selected) || res.va_numbers[0]
                        va = match?.va_number || ''
                      }
                      if (!va && typeof res?.permata_va_number === 'string') {
                        va = res.permata_va_number
                      }
                      setVaCode(va)
                      if (typeof res?.bill_key === 'string') setBillKey(res.bill_key)
                      if (typeof res?.biller_code === 'string') setBillerCode(res.biller_code)
                      lastChargeKeyRef.current = `${orderId}:${selected}`
                      if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
                      onChargeInitiated?.()
                    } catch (e) {
                      const msg = mapErrorToUserMessage(e)
                      setErrorMessage(msg)
                    } finally {
                      setBusy(false)
                      if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
                      chargeTasks.delete(chargeKey)
                    }
                    return
                  }
                  setBusy(true)
                  chargingKeyRef.current = chargeKey
                  const payload: Record<string, any> = {
                    payment_type: 'bank_transfer',
                    transaction_details: { order_id: orderId, gross_amount: amount },
                    bank_transfer: { bank: selected },
                  }
                  const task = postCharge(payload)
                  chargeTasks.set(chargeKey, task)
                  const res = await task
                  // Extract VA / bill info from response
                  let va = ''
                  if (Array.isArray(res?.va_numbers) && res.va_numbers.length) {
                    const match = res.va_numbers.find((v: any) => v?.bank?.toLowerCase() === selected) || res.va_numbers[0]
                    va = match?.va_number || ''
                  }
                  if (!va && typeof res?.permata_va_number === 'string') {
                    va = res.permata_va_number
                  }
                  setVaCode(va)
                  if (typeof res?.bill_key === 'string') setBillKey(res.bill_key)
                  if (typeof res?.biller_code === 'string') setBillerCode(res.biller_code)
                  lastChargeKeyRef.current = `${orderId}:${selected}`
                  if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
                  onChargeInitiated?.()
                } catch (e) {
                  const msg = mapErrorToUserMessage(e)
                  setErrorMessage(msg)
                } finally {
                  setBusy(false)
                  const chargeKey = `${orderId}:${selected}`
                  if (chargingKeyRef.current === chargeKey) chargingKeyRef.current = ''
                  chargeTasks.delete(chargeKey)
                }
              }}
              className="w-full"
            >
              {busy ? (
                <span className="inline-flex items-center justify-center gap-2" role="status" aria-live="polite">
                  <span className="h-4 w-4 animate-spin rounded-full border-2 border-white/70 border-t-transparent" aria-hidden />
                  Membuat VA…
                </span>
              ) : 'Buat VA'}
            </Button>
          )}
          <Button
            variant="outline"
            className="w-full"
            disabled={busy || (!locked && !vaCode && !billKey && recovery !== 'view-existing')}
            onClick={() => nav.toStatus(orderId, 'bank_transfer')}
          >
            Buka halaman status
          </Button>
        </div>
      </div>
    </>
  )
}

// (Hook internal dihapus untuk menjaga kompatibilitas Fast Refresh)