'use client';

import {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react';
import {Check, ChevronDown, Coins, Copy, ExternalLink, FlaskConical, History, Info, LoaderCircle, RefreshCw, ShieldCheck, Wallet} from 'lucide-react';
import {demoWalletView, fundingAmount, fundingId, fundingNetwork, microUsdt, usdtIntentView, usdtStateView, type DemoWallet, type FundingNetwork, type UsdtIntent, type UsdtState} from '@/lib/wallet-funding';
import {dashboardNumber} from '@/lib/dashboard';
import {rialToToman} from '@/lib/trade';
import {useSite} from './site-shell';
import {LocalizedNumberInput} from './localized-number-input';

const demoEvent = 'planck:demo-wallet-updated';
const demoTimestampKey = 'planck-demo-wallet-updated';
const networkName = (network: FundingNetwork) => network === 'ethereum' ? 'Ethereum · ERC-20' : 'Tron · TRC-20';
type DemoRequest = {request_id: string; currency: 'TMN' | 'USDT'; amount: string};
type UsdtRequest = {action: 'create'; request_id: string; network: FundingNetwork; amount: string};
class FundingFailure extends Error {constructor(message: string, readonly definitive = false) {super(message);}}

async function result(response: Response): Promise<Record<string, unknown>> {
  const body: unknown = await response.json().catch(() => null);
  const error = body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : null;
  // Authentication, throttling and conflicts can follow a committed request whose reply was lost.
  // Preserve its idempotency key until a confirmed replay or an input rejection resolves it.
  if (!response.ok) throw new FundingFailure(error || 'دریافت یا ثبت اطلاعات انجام نشد؛ دوباره تلاش کنید.', response.status === 400 || response.status === 422);
  if (!body || typeof body !== 'object' || Array.isArray(body)) throw new FundingFailure('پاسخ سرویس معتبر نبود؛ نتیجه را دوباره بررسی کنید.');
  return body as Record<string, unknown>;
}
const problem = (error: unknown) => error instanceof FundingFailure ? error.message : 'ارتباط کامل نشد. برای بررسی نتیجه، همان درخواست را دوباره ارسال کنید.';
function remember(key: string, request: DemoRequest | UsdtRequest | null) {
  try {if (request) sessionStorage.setItem(key, JSON.stringify(request)); else sessionStorage.removeItem(key);} catch { /* The in-memory request still protects retries if storage is unavailable. */ }
}
function restored(key: string, kind: 'demo' | 'usdt'): DemoRequest | UsdtRequest | null {
  try {
    const raw = sessionStorage.getItem(key); if (!raw) return null;
    const value = JSON.parse(raw) as Record<string, unknown>;
    if (!value || !fundingId(value.request_id)) return null;
    if (kind === 'demo' && (value.currency === 'TMN' || value.currency === 'USDT')) {
      const amount = fundingAmount(value.amount, value.currency === 'TMN' ? 0 : 6, value.currency === 'TMN' ? '100000000' : '100000');
      return {request_id: value.request_id, currency: value.currency, amount: value.currency === 'TMN' ? amount : microUsdt(amount)};
    }
    if (kind === 'usdt' && value.action === 'create' && fundingNetwork(value.network)) return {action: 'create', request_id: value.request_id, network: value.network, amount: microUsdt(fundingAmount(value.amount, 6, '100000'))};
  } catch { /* Discard malformed local drafts, never trust local balances. */ }
  return null;
}
function useOwner() {
  const {user} = useSite(), owner = user?.id;
  const current = useRef(owner), mounted = useRef(true);
  useLayoutEffect(() => {current.current = owner;}, [owner]);
  useEffect(() => {mounted.current = true; return () => {mounted.current = false;};}, []);
  const valid = useCallback((subject: string | undefined) => !!subject && mounted.current && current.current === subject, []);
  return {owner, valid};
}
function announceDemo(owner: string) {
  const at = Date.now();
  window.dispatchEvent(new CustomEvent(demoEvent, {detail: {userId: owner, at}}));
  try {localStorage.setItem(demoTimestampKey, String(at));} catch { /* Cross-tab refresh is optional. */ }
}
function useDemoWallet() {
  const {owner, valid} = useOwner(), [wallet, setWallet] = useState<DemoWallet | null>(null), [loading, setLoading] = useState(true), [error, setError] = useState('');
  const sequence = useRef(0), controller = useRef<AbortController | null>(null);
  const cancelLoad = useCallback(() => {controller.current?.abort(); sequence.current++;}, []);
  const load = useCallback(async () => {
    controller.current?.abort();
    const abort = new AbortController(); controller.current = abort;
    const serial = ++sequence.current;
    if (!owner) {setWallet(null); setLoading(false); return;}
    setLoading(true); setError('');
    try {
      const value = demoWalletView(await result(await fetch('/api/funding/demo', {cache: 'no-store', signal: abort.signal})));
      if (valid(owner) && serial === sequence.current && !abort.signal.aborted) setWallet(value);
    } catch (e) {if (valid(owner) && serial === sequence.current && !abort.signal.aborted) setError(problem(e));}
    finally {if (valid(owner) && serial === sequence.current && !abort.signal.aborted) setLoading(false);}
  }, [owner, valid]);
  useEffect(() => {
    let disposed = false;
    queueMicrotask(() => {if (!disposed) void load();});
    const changed = (event: Event) => {const detail = (event as CustomEvent<{userId?: string; at?: number}>).detail; if (detail?.userId === owner && Number.isFinite(detail.at)) void load();};
    const storage = (event: StorageEvent) => {if (event.key === demoTimestampKey && event.newValue && /^\d+$/.test(event.newValue)) void load();};
    const refresh = () => {if (document.visibilityState === 'visible') void load();};
    const timer = setInterval(refresh, 20000);
    window.addEventListener('focus', refresh); window.addEventListener(demoEvent, changed); window.addEventListener('storage', storage);
    return () => {disposed = true; cancelLoad(); clearInterval(timer); window.removeEventListener('focus', refresh); window.removeEventListener(demoEvent, changed); window.removeEventListener('storage', storage);};
  }, [owner, load, cancelLoad]);
  return {wallet, setWallet, loading, error, load, owner, valid};
}

const demoToman = (rial: string) => /^\d+$/.test(rial) ? rialToToman(BigInt(rial)) : null;
function DemoValues({wallet}: {wallet: DemoWallet}) {
  const {locale, customer} = useSite(), hidden = customer.data?.preferences?.hide_balances;
  return <div className="funding-demo-values"><span>تومان آزمایشی<strong>{hidden ? '••••••' : dashboardNumber(demoToman(wallet.balance_rial), locale, 1)}</strong></span><span>تتر آزمایشی<strong>{hidden ? '••••••' : dashboardNumber(wallet.balance_usdt, locale, 6)} <small>USDT</small></strong></span></div>;
}
function DemoHistory({wallet}: {wallet: DemoWallet}) {
  const {locale, customer} = useSite(), hidden = customer.data?.preferences?.hide_balances;
  if (!wallet.history.length) return null;
  const statusLabels = {pending: 'در انتظار بررسی مدیر', approved: 'تأییدشده · به موجودی آزمایشی اضافه شد', rejected: 'ردشده', problem: 'نیازمند پیگیری'};
  return <details className="funding-demo-history"><summary><History size={15}/><span>آخرین درخواست‌های شارژ آزمایشی</span><ChevronDown size={15}/></summary><ol>{wallet.history.slice(0, 5).map(entry => <li key={entry.id}>
    <span><strong>{hidden ? '••••••' : dashboardNumber(entry.currency === 'IRR' ? demoToman(entry.amount) : entry.amount, locale, entry.currency === 'IRR' ? 1 : 6)}</strong> {entry.currency === 'IRR' ? 'تومان آزمایشی' : 'تتر آزمایشی'}</span>
    <time dateTime={entry.created_at}>{new Intl.DateTimeFormat(locale, {dateStyle: 'short', timeStyle: 'short'}).format(new Date(entry.created_at))}</time>
    <span className={`funding-status${entry.status ? ` is-${entry.status}` : ''}`}>{entry.status ? statusLabels[entry.status] : 'وضعیت بررسی در دسترس نیست'}</span>
    {entry.review_note && <small style={{flexBasis: '100%', overflowWrap: 'anywhere', whiteSpace: 'pre-wrap'}}>نظر مدیریت: {entry.review_note}</small>}
  </li>)}</ol><small>فقط درخواست‌های تأییدشده به موجودی آزمایشی اضافه می‌شوند. این موجودی قابل برداشت نیست.</small></details>;
}

export function DemoBalance() {
  const {user} = useSite();
  return <DemoBalanceBody key={user?.id || 'guest'}/>;
}
function DemoBalanceBody() {
  const {wallet, loading, error, load, owner} = useDemoWallet();
  if (!owner) return null;
  return <section className="wallet-funding funding-demo-balance" aria-labelledby="demo-balance-title" aria-busy={loading}>
    <header className="funding-heading"><span className="funding-icon"><FlaskConical size={21}/></span><div><h3 id="demo-balance-title">موجودی آزمایشی</h3><p>غیرقابل برداشت · برای آزمایش خرید و فروش در آینده</p></div><button type="button" className="funding-icon-button" aria-label="تازه‌سازی موجودی آزمایشی" disabled={loading} onClick={() => void load()}><RefreshCw size={16} className={loading ? 'funding-spin' : ''}/></button></header>
    {wallet ? <><DemoValues wallet={wallet}/><DemoHistory wallet={wallet}/></> : loading ? <p className="funding-note"><LoaderCircle size={15} className="funding-spin"/>در حال دریافت موجودی آزمایشی…</p> : <p className="funding-note">موجودی آزمایشی در دسترس نیست.</p>}
    {error && <p className="funding-error" role="alert">{error}</p>}
  </section>;
}

export function DemoFunding(props: {amountToman: string; onFunded: () => void; onLockChange?: (locked: boolean) => void}) {
  const {user} = useSite();
  return <DemoFundingBody key={user?.id || 'guest'} {...props}/>;
}
function DemoFundingBody({amountToman, onFunded, onLockChange}: {amountToman: string; onFunded: () => void; onLockChange?: (locked: boolean) => void}) {
  const {locale} = useSite(), {wallet, setWallet, loading, error: loadError, load, owner, valid} = useDemoWallet();
  const [currency, setCurrency] = useState<'TMN' | 'USDT'>('TMN'), [usdt, setUsdt] = useState(''), [pending, setPending] = useState<DemoRequest | null>(null), [busy, setBusy] = useState(false), [error, setError] = useState(''), [notice, setNotice] = useState(''), [expanded, setExpanded] = useState(false);
  const lock = useRef(false), draft = useRef<DemoRequest | null>(null), uncertain = useRef(false), storageKey = `planck:demo-funding:${owner || 'guest'}`;
  useEffect(() => {let disposed = false; queueMicrotask(() => {if (disposed) return; const saved = restored(storageKey, 'demo') as DemoRequest | null; draft.current = saved; uncertain.current = !!saved; setPending(saved); if (saved) {setExpanded(true); setCurrency(saved.currency); if (saved.currency === 'USDT') setUsdt(saved.amount);}}); return () => {disposed = true;};}, [storageKey]);
  useEffect(() => {onLockChange?.(!!pending); return () => onLockChange?.(false);}, [pending, onLockChange]);
  const amount = pending?.amount ?? (currency === 'TMN' ? amountToman : usdt);
  let validAmount = false;
  try {if (wallet) {fundingAmount(amount, currency === 'TMN' ? 0 : 6, currency === 'TMN' ? wallet.limits.max_amount_toman : wallet.limits.max_amount_usdt); validAmount = true;}} catch { /* Validation is displayed before sending. */ }
  async function fund() {
    if (!owner || !valid(owner) || lock.current || (!pending && (!wallet?.enabled || !validAmount))) return;
    let request = draft.current;
    if (!request) {
      try {const atomic = fundingAmount(amount, currency === 'TMN' ? 0 : 6, currency === 'TMN' ? wallet!.limits.max_amount_toman : wallet!.limits.max_amount_usdt); request = {request_id: crypto.randomUUID(), currency, amount: currency === 'TMN' ? atomic : microUsdt(atomic)};}
      catch {setError('مبلغ مثبت و معتبر، در محدوده مجاز وارد کنید.'); return;}
      draft.current = request; uncertain.current = false; remember(storageKey, request); setPending(request); setExpanded(true);
    }
    lock.current = true; setBusy(true); setError(''); setNotice('');
    try {
      const value = await result(await fetch('/api/funding/demo', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(request), signal: AbortSignal.timeout(30_000)}));
      const updated = demoWalletView(value);
      if (!valid(owner)) return;
      if (!fundingId(value.review_id) || !['pending', 'approved', 'rejected', 'problem'].includes(String(value.status))) throw new FundingFailure('نتیجه ثبت درخواست مشخص نیست؛ همان درخواست را دوباره بررسی کنید.');
      setWallet(updated); draft.current = null; uncertain.current = false; setPending(null); remember(storageKey, null);
      setNotice(value.credited === true ? 'شارژ آزمایشی تأیید و به موجودی اضافه شد؛ این موجودی قابل برداشت نیست.' : value.status === 'pending' ? 'درخواست شارژ آزمایشی ثبت شد و در انتظار تأیید مدیر است. نتیجه در تاریخچه و اعلان‌ها نمایش داده می‌شود.' : 'نتیجه بررسی این درخواست در تاریخچه واریز و برداشت قابل مشاهده است.');
      announceDemo(owner); onFunded();
    } catch (e) {
      if (!valid(owner)) return;
      setError(problem(e));
      if (e instanceof FundingFailure && e.definitive && !uncertain.current) {draft.current = null; setPending(null); remember(storageKey, null);} else uncertain.current = true;
    } finally {if (valid(owner)) {lock.current = false; setBusy(false);}}
  }
  return <details className="wallet-funding funding-demo" open={expanded} onToggle={event => setExpanded(event.currentTarget.open)}>
    <summary><span className="funding-icon"><FlaskConical size={22}/></span><span><strong>شارژ آزمایشی</strong><small>تومان یا تتر آزمایشی · غیرقابل برداشت</small></span><ChevronDown size={18}/></summary>
    <div className="funding-demo-body" aria-busy={busy || loading}>
      <p className="funding-note"><Info size={17}/>این موجودی جدا از دارایی واقعی شماست. پس از تأیید مدیر به موجودی آزمایشی اضافه می‌شود و قابل برداشت نیست.</p>
      {wallet && <><DemoValues wallet={wallet}/><DemoHistory wallet={wallet}/></>}
      <fieldset className="funding-segment" aria-label="واحد شارژ آزمایشی">{(['TMN', 'USDT'] as const).map(unit => <button type="button" key={unit} disabled={busy || !!pending} aria-pressed={currency === unit} onClick={() => {setCurrency(unit); setError(''); setNotice('');}}>{unit === 'TMN' ? 'تومان آزمایشی' : 'تتر آزمایشی'}</button>)}</fieldset>
      {currency === 'USDT' ? <label className="funding-field" htmlFor="funding-demo-amount"><span>مبلغ تتر آزمایشی</span><LocalizedNumberInput id="funding-demo-amount" value={pending?.amount ?? usdt} onValueChange={setUsdt} locale={locale} disabled={busy || !!pending} maxLength={24} placeholder="۰"/><small>حداکثر {wallet ? dashboardNumber(wallet.limits.max_amount_usdt, locale, 0) : '—'} تتر در هر شارژ</small></label> : <p className="funding-amount-summary">مبلغ انتخاب‌شده: <strong>{amount ? dashboardNumber(amount, locale, 0) : '—'} تومان</strong><small>{pending ? 'مبلغ این درخواست تا مشخص شدن نتیجه ثابت می‌ماند.' : 'مبلغ را در کادر مبلغ واریز بالای صفحه وارد کنید.'}</small></p>}
      {loading && !wallet && <p className="funding-note"><LoaderCircle size={15} className="funding-spin"/>در حال دریافت تنظیمات…</p>}
      {loadError && <p className="funding-error" role="alert">{loadError} <button type="button" onClick={() => void load()} disabled={loading}>تلاش دوباره</button></p>}
      {wallet && !wallet.enabled && <p className="funding-note">شارژ آزمایشی اکنون فعال نیست.</p>}
      {pending && !busy && <p className="funding-note">برای مشخص شدن نتیجه، همین درخواست را دوباره بررسی کنید؛ مبلغ و شناسه آن تغییر نمی‌کند.</p>}
      <button type="button" className="funding-primary" disabled={!owner || busy || (!pending && (!wallet?.enabled || !validAmount))} onClick={() => void fund()}>{busy ? <LoaderCircle size={17} className="funding-spin"/> : <FlaskConical size={17}/>}<span>{busy ? 'در حال بررسی شارژ…' : pending ? 'بررسی دوباره همان درخواست' : 'ثبت درخواست شارژ آزمایشی'}</span></button>
      {error && <p className="funding-error" role="alert">{error}</p>}{notice && <output className="funding-pending-note">{notice}</output>}
    </div>
  </details>;
}

function CopyValue({value, label, prominent = false}: {value: string; label: string; prominent?: boolean}) {
  const [copied, setCopied] = useState<'yes' | 'error' | null>(null);
  useEffect(() => {if (copied) {const timer = setTimeout(() => setCopied(null), 2500); return () => clearTimeout(timer);}}, [copied]);
  return <div className={`funding-copy${prominent ? ' is-prominent' : ''}`}><bdi>{value}</bdi><button type="button" aria-label={label} onClick={async () => {try {await navigator.clipboard.writeText(value); setCopied('yes');} catch {setCopied('error');}}}>{copied === 'yes' ? <Check size={17}/> : <Copy size={17}/>}</button>{copied && <output>{copied === 'yes' ? 'کپی شد' : 'کپی انجام نشد؛ متن را انتخاب و کپی کنید.'}</output>}</div>;
}
function explorer(network: FundingNetwork, hash: string | null) {
  if (!hash) return null;
  if (network === 'ethereum' && /^0x[a-fA-F0-9]{64}$/.test(hash)) return `https://etherscan.io/tx/${hash}`;
  if (network === 'tron' && /^[a-fA-F0-9]{64}$/.test(hash)) return `https://tronscan.org/#/transaction/${hash}`;
  return null;
}
const statusLabel = (status: string) => ({pending: 'در انتظار تأیید', credited: 'واریز تأیید و شارژ شد', expired: 'مهلت واریز تمام شده', review: 'در انتظار تأیید مدیر', problem: 'نیازمند بررسی', rejected: 'ردشده'}[status] || 'در انتظار بررسی');
const intentStatus = (intent: UsdtIntent, now: number) => intent.status === 'credited' ? 'credited' : ['rejected','problem'].includes(intent.review_decision || '') ? intent.review_decision! : intent.verification_status === 'verified' ? 'review' : intent.status === 'pending' && Date.parse(intent.expires_at) <= now ? 'expired' : intent.status;

export function UsdtFunding() {
  const {user} = useSite();
  return <UsdtFundingBody key={user?.id || 'guest'}/>;
}
function UsdtFundingBody() {
  const {locale, customer} = useSite(), {owner, valid} = useOwner(), customerReload = customer.reload;
  const [state, setState] = useState<UsdtState | null>(null), [loading, setLoading] = useState(true), [loadError, setLoadError] = useState(''), [network, setNetwork] = useState<FundingNetwork>('ethereum'), [amount, setAmount] = useState('');
  const [pending, setPending] = useState<UsdtRequest | null>(null), [creating, setCreating] = useState(false), [selectedId, setSelectedId] = useState(''), [hashes, setHashes] = useState<Record<string, string>>({}), [submitted, setSubmitted] = useState<Record<string, string>>({});
  const [checking, setChecking] = useState(''), [error, setError] = useState(''), [notice, setNotice] = useState(''), [now, setNow] = useState(() => Date.now()), [stoppedPolling, setStoppedPolling] = useState<Record<string, boolean>>({});
  const creatingLock = useRef(false), checkingLock = useRef(false), draft = useRef<UsdtRequest | null>(null), uncertain = useRef(false), loadVersion = useRef(0), loadController = useRef<AbortController | null>(null), credited = useRef(new Set<string>());
  const cancelLoad = useCallback(() => {loadController.current?.abort(); loadVersion.current++;}, []);
  const storageKey = `planck:usdt-funding:${owner || 'guest'}`;
  const applyIntent = useCallback((intent: UsdtIntent) => {
    loadVersion.current++; loadController.current?.abort(); setLoading(false);
    setState(current => current ? {...current, intents: [intent, ...current.intents.filter(row => row.id !== intent.id)]} : {networks: [], intents: [intent]});
    if (intent.status === 'credited' && !credited.current.has(intent.id)) {credited.current.add(intent.id); void customerReload();}
  }, [customerReload]);
  const load = useCallback(async () => {
    if (!owner) {setLoading(false); return;}
    loadController.current?.abort(); const abort = new AbortController(); loadController.current = abort;
    const serial = ++loadVersion.current; setLoading(true); setLoadError('');
    try {
      const value = usdtStateView(await result(await fetch('/api/funding/usdt', {cache: 'no-store', signal: abort.signal})));
      if (!valid(owner) || abort.signal.aborted || serial !== loadVersion.current) return;
      setState(value);
      let refreshBalance = false;
      for (const intent of value.intents) if (intent.status === 'credited' && !credited.current.has(intent.id)) {credited.current.add(intent.id); refreshBalance = true;}
      if (refreshBalance) void customerReload();
      setSelectedId(current => value.intents.some(row => row.id === current) ? current : value.intents.find(row => row.status === 'pending')?.id || value.intents[0]?.id || '');
      if (!draft.current) setNetwork(current => value.networks.some(row => row.network === current && row.enabled && row.address) ? current : value.networks.find(row => row.enabled && row.address)?.network || current);
    } catch (e) {if (valid(owner) && !abort.signal.aborted && serial === loadVersion.current) setLoadError(problem(e));}
    finally {if (valid(owner) && !abort.signal.aborted && serial === loadVersion.current) setLoading(false);}
  }, [owner, valid, customerReload]);
  useEffect(() => {
    let disposed = false;
    queueMicrotask(() => {if (disposed) return; const saved = restored(storageKey, 'usdt') as UsdtRequest | null; draft.current = saved; uncertain.current = !!saved; setPending(saved); if (saved) {setNetwork(saved.network); setAmount(saved.amount);} void load();});
    const timer = setInterval(() => setNow(Date.now()), 1000);
    return () => {disposed = true; cancelLoad(); clearInterval(timer);};
  }, [load, storageKey, cancelLoad]);

  useEffect(() => {
    const refresh = () => {if (document.visibilityState === 'visible' && !creatingLock.current && !checkingLock.current) void load();};
    const timer = setInterval(refresh, 15000);
    window.addEventListener('focus', refresh); document.addEventListener('visibilitychange', refresh);
    return () => {clearInterval(timer); window.removeEventListener('focus', refresh); document.removeEventListener('visibilitychange', refresh);};
  }, [load]);

  const selected = state?.intents.find(row => row.id === selectedId), currentNetwork = state?.networks.find(row => row.network === network), configured = !!currentNetwork?.enabled && !!currentNetwork.address;
  const existing = state?.intents.find(row => row.network === network && row.status === 'pending' && Date.parse(row.expires_at) > now);
  let amountValid = false; try {fundingAmount(amount, 6, '100000'); amountValid = true;} catch { /* Invalid amounts cannot be submitted. */ }
  async function create() {
    if (!owner || !valid(owner) || creatingLock.current || checkingLock.current || (!draft.current && (!configured || !amountValid || existing))) return;
    let request = draft.current;
    if (!request) {request = {action: 'create', request_id: crypto.randomUUID(), network, amount: microUsdt(fundingAmount(amount, 6, '100000'))}; draft.current = request; uncertain.current = false; setPending(request); remember(storageKey, request);}
    creatingLock.current = true; setCreating(true); setError(''); setNotice('');
    try {
      const intent = usdtIntentView(await result(await fetch('/api/funding/usdt', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(request), signal: AbortSignal.timeout(30_000)})));
      if (!valid(owner)) return;
      if (intent.network !== request.network || intent.requested_micro !== fundingAmount(request.amount, 6, '100000')) throw new FundingFailure('پاسخ درخواست واریز معتبر نبود؛ همان درخواست را دوباره بررسی کنید.');
      applyIntent(intent); setSelectedId(intent.id); draft.current = null; uncertain.current = false; setPending(null); remember(storageKey, null);
    } catch (e) {
      if (!valid(owner)) return; setError(problem(e));
      if (e instanceof FundingFailure && e.definitive && !uncertain.current) {draft.current = null; setPending(null); remember(storageKey, null);} else uncertain.current = true;
      void load();
    } finally {if (valid(owner)) {creatingLock.current = false; setCreating(false);}}
  }
  const verify = useCallback(async (intent: UsdtIntent, hash: string, automatic = false) => {
    if (!owner || !valid(owner) || checkingLock.current || creatingLock.current || intent.status === 'credited') return;
    const normalized = hash.trim().toLowerCase();
    if (!(intent.network === 'ethereum' ? /^0x[a-f0-9]{64}$/ : /^[a-f0-9]{64}$/).test(normalized)) {if (!automatic) setError('شناسه تراکنش معتبر برای شبکه انتخاب‌شده وارد کنید.'); return;}
    checkingLock.current = true; setChecking(intent.id);
    if (!automatic) {setError(''); setNotice(''); setStoppedPolling(current => ({...current, [intent.id]: false}));}
    if (!automatic) setSubmitted(current => ({...current, [intent.id]: normalized}));
    try {
      // Background checks read the server's candidate; they must not overwrite a hash corrected in another tab.
      const value = await result(await fetch('/api/funding/usdt', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({action: 'verify', intent_id: intent.id, ...(!automatic ? {transaction_hash: normalized} : {})}), signal: AbortSignal.timeout(30_000)}));
      const updated = usdtIntentView(value.intent);
      if (!valid(owner)) return;
      if (updated.id !== intent.id || updated.network !== intent.network || updated.amount_micro !== intent.amount_micro) throw new FundingFailure('پاسخ بررسی واریز معتبر نبود؛ دوباره تلاش کنید.');
      applyIntent(updated);
      if (updated.status === 'credited') {setNotice('واریز تتر از شبکه تأیید شد و موجودی کیف پول به‌روز شد.'); setError('');}
      else if (updated.verification_status === 'verified') setNotice('واریز در شبکه تأیید شد و اکنون در انتظار بررسی مدیر است. دوباره وجه ارسال نکنید.');
      else if (!automatic) setNotice('شناسه تراکنش ثبت شد؛ واریز هنوز تأیید نشده است. بررسی شبکه هر ۲۰ ثانیه ادامه دارد.');
    } catch (e) {if (valid(owner)) {setError(problem(e)); if (e instanceof FundingFailure && e.definitive) setStoppedPolling(current => ({...current, [intent.id]: true}));}}
    finally {if (valid(owner)) {checkingLock.current = false; setChecking('');}}
  }, [owner, valid, applyIntent]);
  const pollHash = selected ? selected.candidate_tx_hash || submitted[selected.id] || '' : '';
  const polling = useRef<{selected: UsdtIntent | undefined; hash: string; stopped: Record<string, boolean>}>({selected: undefined, hash: '', stopped: {}});
  useLayoutEffect(() => {polling.current = {selected, hash: pollHash, stopped: stoppedPolling};}, [selected, pollHash, stoppedPolling]);
  useEffect(() => {
    const timer = setInterval(() => {
      const {selected: current, hash, stopped} = polling.current;
      if (!current || !hash || current.status === 'credited' || current.verification_status === 'verified' || ['rejected','problem'].includes(current.review_decision || '')) return;
      if (document.visibilityState === 'visible' && Date.now() - Date.parse(current.expires_at) <= 7 * 86400_000 && !stopped[current.id]) void verify(current, hash, true);
    }, 20_000);
    return () => clearInterval(timer);
  }, [verify]);
  const expired = !!selected && (selected.status === 'expired' || Date.parse(selected.expires_at) <= now), seconds = selected ? Math.max(0, Math.ceil((Date.parse(selected.expires_at) - now) / 1000)) : 0;
  const countdown = `${Math.floor(seconds / 60).toString().padStart(2, '0')}:${(seconds % 60).toString().padStart(2, '0')}`;
  const selectedStatus = selected ? intentStatus(selected, now) : 'pending';
  const selectedHash = selected ? hashes[selected.id] ?? submitted[selected.id] ?? selected.candidate_tx_hash ?? '' : '';

  return <section className="wallet-funding funding-usdt" dir={locale === 'en' ? 'ltr' : 'rtl'} aria-labelledby="usdt-funding-title">
    <header className="funding-heading"><span className="funding-icon"><Coins size={25}/></span><div><h2 id="usdt-funding-title">واریز تتر به کیف پول</h2><p>واریز USDT در شبکه اتریوم یا ترون</p></div><button type="button" className="funding-icon-button" aria-label="تازه‌سازی واریزهای تتر" disabled={loading || creating || !!checking} onClick={() => void load()}><RefreshCw size={17} className={loading ? 'funding-spin' : ''}/></button></header>
    {loading && !state && <p className="funding-note"><LoaderCircle size={16} className="funding-spin"/>در حال دریافت شبکه‌ها و درخواست‌ها…</p>}
    {loadError && <p className="funding-error" role="alert">{loadError}</p>}
    <form className="funding-create" onSubmit={event => {event.preventDefault(); void create();}} aria-busy={creating}>
      <fieldset className="funding-segment" aria-label="شبکه واریز تتر">{(['ethereum', 'tron'] as const).map(value => <button type="button" key={value} aria-pressed={network === value} disabled={creating || !!pending} onClick={() => {setNetwork(value); setError(''); setNotice('');}}><bdi>{networkName(value)}</bdi></button>)}</fieldset>
      {!configured && !loading && <p className="funding-note"><Info size={17}/>تنظیمات مقصد این شبکه باید توسط مدیریت تکمیل و فعال شود. فعلاً امکان ایجاد درخواست واریز در این شبکه وجود ندارد.</p>}
      <label className="funding-field" htmlFor="funding-usdt-amount"><span>مبلغ موردنظر (USDT)</span><LocalizedNumberInput id="funding-usdt-amount" value={pending?.amount ?? amount} onValueChange={setAmount} locale={locale} maxLength={24} disabled={creating || !!pending || !configured} placeholder="۰"/><small>پس از ایجاد درخواست، مبلغ دقیق مخصوص این واریز نمایش داده می‌شود.</small></label>
      {existing && !pending && <p className="funding-note">در این شبکه یک درخواست باز دارید. <button type="button" onClick={() => {setSelectedId(existing.id); setError(''); setNotice('');}}>نمایش درخواست باز</button></p>}
      {pending && <p className="funding-note">نتیجه درخواست هنوز مشخص نیست. برای جلوگیری از ثبت تکراری، مبلغ و شبکه ثابت می‌ماند.</p>}
      <button className="funding-primary" disabled={!owner || creating || !!checking || (!pending && (!configured || !amountValid || !!existing))}>{creating ? <LoaderCircle size={17} className="funding-spin"/> : <Wallet size={17}/>}<span>{creating ? 'در حال دریافت دستور واریز…' : pending ? 'دریافت نتیجه همان درخواست' : 'دریافت مبلغ دقیق و نشانی واریز'}</span></button>
    </form>
    {selected && <article className="funding-intent" aria-labelledby="funding-intent-title">
      <header><h3 id="funding-intent-title">درخواست واریز <bdi>{networkName(selected.network)}</bdi></h3><span className={`funding-status is-${selectedStatus}`}>{statusLabel(selectedStatus)}</span></header>
      {selected.status === 'credited' ? <p className="funding-success"><ShieldCheck size={18}/>این واریز تأیید و به موجودی واقعی کیف پول اضافه شده است.</p> : selected.verification_status === 'verified' || ['rejected','problem'].includes(selected.review_decision || '') ? <p className="funding-note">{selected.verification_status === 'verified' ? 'تأیید شبکه دریافت شد. نتیجه بررسی مدیر در تاریخچه نمایش داده می‌شود.' : 'این واریز به بررسی پشتیبانی نیاز دارد.'} دوباره وجه ارسال نکنید. {selected.review_note}</p> : expired ? <p className="funding-error">مهلت یک‌ساعته این درخواست تمام شده است. واریز جدید انجام ندهید؛ اگر قبلاً پرداخت کرده‌اید، شناسه تراکنش را برای پیگیری وارد کنید.</p> : <>
        <p className="funding-exact-label">دقیقاً همین مبلغ را ارسال کنید</p><CopyValue value={`${microUsdt(selected.amount_micro)}`} label="کپی مبلغ دقیق تتر" prominent/><span className="funding-usdt-unit">USDT</span>
        <p className="funding-note">نشانی مقصد میان کاربران مشترک است؛ مبلغ دقیق، واریز شما را شناسایی می‌کند. اختلاف با مبلغ درخواستی کمتر از ۰٫۰۰۱ تتر است. مبلغ دریافتی مقصد باید دقیقاً مطابق این عدد باشد.</p>
        <p className="funding-address-label">نشانی مقصد فقط در شبکه <bdi>{networkName(selected.network)}</bdi></p><CopyValue value={selected.address} label="کپی نشانی مقصد تتر"/>
        <p className="funding-expiry">مهلت واریز <bdi>{countdown}</bdi><span>تا <time dateTime={selected.expires_at}>{new Intl.DateTimeFormat(locale, {dateStyle: 'short', timeStyle: 'short'}).format(new Date(selected.expires_at))}</time></span></p>
      </>}
      {selected.status !== 'credited' && selected.verification_status !== 'verified' && !['rejected','problem'].includes(selected.review_decision || '') && <form className="funding-verify" onSubmit={event => {event.preventDefault(); void verify(selected, selectedHash);}} aria-busy={checking === selected.id}>
        <label className="funding-field"><span>شناسه تراکنش پس از انتقال (TxID)</span><input dir="ltr" value={selectedHash} onChange={event => setHashes(current => ({...current, [selected.id]: event.target.value}))} disabled={!!checking} maxLength={66} autoComplete="off" autoCapitalize="none" spellCheck={false}/><small>پس از تطبیق مبلغ و مقصد و تأیید شبکه، واریز برای تأیید مدیر ارسال می‌شود.</small></label>
        <button type="submit" className="funding-secondary" disabled={creating || !!checking || !selectedHash.trim()}>{checking === selected.id ? <LoaderCircle size={16} className="funding-spin"/> : <RefreshCw size={16}/>}بررسی واریز از شبکه</button>
        {pollHash && !stoppedPolling[selected.id] && <small className="funding-poll-note">این تراکنش هنگام باز بودن صفحه، هر ۲۰ ثانیه بررسی می‌شود.</small>}
      </form>}
    </article>}
    {error && <p className="funding-error" role="alert">{error}</p>}{notice && <output className="funding-pending-note">{notice}</output>}
    {!!state?.intents.length && <section className="funding-history" aria-labelledby="usdt-history-title"><h3 id="usdt-history-title"><History size={19}/>تاریخچه درخواست‌های تتر</h3>{state.intents.map(intent => {
      const status = intentStatus(intent, now), hash = intent.tx_hash || intent.candidate_tx_hash, href = explorer(intent.network, hash);
      return <article key={intent.id}><button type="button" className="funding-history-select" disabled={creating || !!checking} aria-pressed={selectedId === intent.id} onClick={() => {setSelectedId(intent.id); setError(''); setNotice('');}}><span><bdi>{customer.data?.preferences?.hide_balances ? '••••••' : dashboardNumber(microUsdt(intent.amount_micro), locale, 6)} USDT</bdi><small><bdi>{networkName(intent.network)}</bdi> · <time dateTime={intent.created_at}>{new Intl.DateTimeFormat(locale, {dateStyle: 'short', timeStyle: 'short'}).format(new Date(intent.created_at))}</time></small></span><span className={`funding-status is-${status}`}>{statusLabel(status)}</span></button>{href && <a className="funding-explorer" href={href} target="_blank" rel="noopener noreferrer"><bdi>{hash}</bdi><ExternalLink size={13}/><span className="sr-only">مشاهده تراکنش در مرورگر شبکه</span></a>}</article>;
    })}</section>}
  </section>;
}
