'use client';

import {useCallback, useEffect, useRef, useState} from 'react';
import {ArrowUpLeft, CheckCircle2, Clock3, CreditCard, Info, LoaderCircle, Plus, RefreshCw, ShieldCheck} from 'lucide-react';
import {dashboardNumber} from '@/lib/dashboard';
import {depositAmountRial} from '@/lib/cash-wallet';
import {rialToToman} from '@/lib/trade';
import {isTcarttId, tcarttPayment, type TcarttAvailability, type TcarttPayment} from '@/lib/tcartt-payment';
import {useSite} from './site-shell';

type Attempt = {requestId: string | null; paymentId: string | null; amountToman: string | null};
type Props = {
  amountToman: string; disabled: boolean; availability: TcarttAvailability | null; availabilityError: string;
  requestedPaymentId?: string | null; requestedRequestId?: string | null;
  onLockChange: (locked: boolean) => void; onAmountRestore: (amount: string) => void;
  onChanged: (payment: TcarttPayment) => void; onAuthRequired: () => void; onRefreshAvailability: () => void;
};
const endpoint = '/api/customer/wallet/tcartt';
const integer = BigInt;
const lookup = (item: Attempt) => item.paymentId ? {paymentId: item.paymentId} : {requestId: item.requestId};
const awaiting = (payment: TcarttPayment | null) => !!payment && ['created', 'pending', 'creation_unknown'].includes(payment.status);
const settled = (payment: TcarttPayment | null) => !!payment && ['credited', 'failed', 'cancelled', 'expired', 'pending_review'].includes(payment.status);

/** The browser only requests an invoice or a status check. It never confirms a payment or credits a wallet. */
export function TcarttDeposit(props: Props) {
  const {locale, user} = useSite();
  const userId = user?.id;
  const {onLockChange, requestedPaymentId, requestedRequestId} = props;
  const t = (fa: string, en: string, ar: string) => locale === 'en' ? en : locale === 'ar' ? ar : fa;
  const [payment, setPayment] = useState<TcarttPayment | null>(null), [attempt, setAttempt] = useState<Attempt | null>(null);
  const [busy, setBusy] = useState<'start' | 'status' | null>(null), [error, setError] = useState(''), [restored, setRestored] = useState(false), [canRetry, setCanRetry] = useState(false);
  const callbacks = useRef(props);
  useEffect(() => {callbacks.current = props;}, [props]);
  const lock = useRef(false), mounted = useRef(false), attemptRef = useRef<Attempt | null>(null), lastState = useRef(''), restoreTarget = useRef('');
  const storageKey = userId ? `planck-tcartt-attempt:${userId}` : null;
  const fallback = t('وضعیت واریز دریافت نشد. پیش از پرداخت دوباره، همین درخواست را بررسی کنید.', 'Could not retrieve the deposit status. Check this request before paying again.', 'تعذر الحصول على حالة الإيداع. تحقق من هذا الطلب قبل الدفع مرة أخرى.');
  const pending = awaiting(payment) || (!!attempt && !payment);
  const invoiceKnown = !!payment && !['created', 'creation_unknown'].includes(payment.status);
  const amountRial = depositAmountRial(props.amountToman), valid = !!amountRial && integer(amountRial) >= integer(10000);
  const money = (rial: string) => dashboardNumber(rialToToman(integer(rial)), locale, 0);
  const currency = t('تومان', 'TMN', 'تومان');

  const remember = useCallback((item: Attempt | null) => {
    attemptRef.current = item; setAttempt(item);
    if (storageKey) try {if (item) sessionStorage.setItem(storageKey, JSON.stringify(item)); else sessionStorage.removeItem(storageKey);} catch { /* URL recovery remains available if storage is blocked. */ }
    const url = new URL(window.location.href);
    url.searchParams.delete('tcartt_payment'); url.searchParams.delete('tcartt_request');
    if (item?.paymentId) url.searchParams.set('tcartt_payment', item.paymentId);
    else if (item?.requestId) url.searchParams.set('tcartt_request', item.requestId);
    window.history.replaceState(window.history.state, '', url);
  }, [storageKey]);

  const apply = useCallback((value: TcarttPayment, previous: Attempt | null) => {
    setPayment(value); setCanRetry(false);
    const amount = rialToToman(integer(value.baseAmountRial));
    remember({requestId: previous?.requestId || null, paymentId: value.paymentId, amountToman: amount});
    callbacks.current.onAmountRestore(amount);
    const stateKey = `${value.paymentId}:${value.status}:${value.reviewDecision}`;
    if (lastState.current !== stateKey) {lastState.current = stateKey; callbacks.current.onChanged(value);}
  }, [remember]);

  const check = useCallback(async (item: Attempt) => {
    if (lock.current || !userId || (!item.paymentId && !item.requestId)) return;
    lock.current = true; setBusy('status'); setError('');
    try {
      const response = await fetch(endpoint, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({action: 'status', ...lookup(item)}), signal: AbortSignal.timeout(30000)});
      const result: unknown = await response.json().catch(() => null), value = tcarttPayment(result);
      if (!mounted.current) return;
      if (!response.ok || !value || (item.paymentId && value.paymentId !== item.paymentId)) {
        if (response.status === 401) callbacks.current.onAuthRequired();
        // A server-confirmed absent request can be retried with its SAME id and amount.
        if (response.status === 404 && result && typeof result === 'object' && 'code' in result && result.code === 'payment_not_found' && !item.paymentId && item.requestId && item.amountToman) setCanRetry(true);
        throw new Error(result && typeof result === 'object' && 'error' in result && typeof result.error === 'string' ? result.error : fallback);
      }
      apply(value, item);
    } catch (e) {if (mounted.current) setError(e instanceof Error && !['TimeoutError', 'TypeError', 'AbortError'].includes(e.name) ? e.message : fallback);}
    finally {lock.current = false; if (mounted.current) setBusy(null);}
  }, [userId, fallback, apply]);



  useEffect(() => {
    mounted.current = true;
    return () => {mounted.current = false; callbacks.current.onLockChange(false);};
  }, [storageKey]);

  useEffect(() => {
    const target = `${storageKey}:${requestedPaymentId || ''}:${requestedRequestId || ''}`;
    if (restoreTarget.current === target) return;
    restoreTarget.current = target;
    let saved: Attempt | null = null;
    if (storageKey) try {
      const value = JSON.parse(sessionStorage.getItem(storageKey) || 'null');
      if (value && (isTcarttId(value.requestId) || isTcarttId(value.paymentId)) && (value.amountToman === null || typeof value.amountToman === 'string' && /^\d{1,12}$/.test(value.amountToman))) {
        saved = {requestId: isTcarttId(value.requestId) ? value.requestId : null, paymentId: isTcarttId(value.paymentId) ? value.paymentId : null, amountToman: value.amountToman};
      }
    } catch { /* Corrupt or unavailable browser storage must not create an invoice. */ }
    if (isTcarttId(requestedPaymentId)) saved = {requestId: null, paymentId: requestedPaymentId, amountToman: saved?.paymentId === requestedPaymentId ? saved.amountToman : null};
    else if (isTcarttId(requestedRequestId)) saved = {requestId: requestedRequestId, paymentId: null, amountToman: saved?.requestId === requestedRequestId ? saved.amountToman : null};
    if (saved) {attemptRef.current = saved; setAttempt(saved); if (saved.amountToman) callbacks.current.onAmountRestore(saved.amountToman); void check(saved);}
    setRestored(true);
  }, [storageKey, requestedPaymentId, requestedRequestId, check]);

  useEffect(() => {onLockChange(!!busy || pending);}, [busy, pending, onLockChange]);
  useEffect(() => {
    if (!payment || !['created', 'pending', 'pending_review'].includes(payment.status) || ['rejected', 'problem'].includes(payment.reviewDecision || '')) return;
    const refresh = () => {if (document.visibilityState === 'visible' && attemptRef.current) void check(attemptRef.current);};
    const timer = window.setInterval(refresh, 15000);
    window.addEventListener('focus', refresh); document.addEventListener('visibilitychange', refresh);
    return () => {window.clearInterval(timer); window.removeEventListener('focus', refresh); document.removeEventListener('visibilitychange', refresh);};
  }, [payment, check]);

  async function start() {
    if (!restored || lock.current || !user || props.disabled || !props.availability?.ready || !valid || (attemptRef.current && !canRetry)) return;
    const item: Attempt = attemptRef.current?.requestId && canRetry ? attemptRef.current : {requestId: crypto.randomUUID(), paymentId: null, amountToman: rialToToman(integer(amountRial!))};
    remember(item); setCanRetry(false); setBusy('start'); setError(''); lock.current = true;
    try {
      const response = await fetch(endpoint, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({action: 'start', requestId: item.requestId, amountToman: item.amountToman}), signal: AbortSignal.timeout(30000)});
      const result: unknown = await response.json().catch(() => null), value = tcarttPayment(result);
      if (!mounted.current) return;
      if (!response.ok || !value) {
        if (response.status === 401) callbacks.current.onAuthRequired();
        if ([400, 401, 403, 422, 429].includes(response.status)) setCanRetry(true);
        throw new Error(result && typeof result === 'object' && 'error' in result && typeof result.error === 'string' ? result.error : fallback);
      }
      apply(value, item);
    } catch (e) {if (mounted.current) setError(e instanceof Error && !['TimeoutError', 'TypeError', 'AbortError'].includes(e.name) ? e.message : fallback);}
    finally {lock.current = false; if (mounted.current) setBusy(null);}
  }

  const problem = !!payment && (['failed', 'cancelled', 'expired'].includes(payment.status) || ['rejected', 'problem'].includes(payment.reviewDecision || ''));
  const paid = payment?.status === 'credited';
  const status = paid ? t('تأیید شد و به کیف پول اضافه شد', 'Approved and credited to your wallet', 'تمت الموافقة وإضافة المبلغ إلى المحفظة')
    : payment?.reviewDecision === 'rejected' ? t('درخواست توسط مدیریت رد شد', 'Request rejected by the administrator', 'رفض المسؤول الطلب')
    : payment?.reviewDecision === 'problem' ? t('این واریز نیاز به پیگیری دارد', 'This deposit needs attention', 'يتطلب هذا الإيداع المتابعة')
    : payment?.status === 'pending_review' && payment.reviewDecision === 'approved' ? t('درخواست تأیید شد؛ ثبت اعتبار در حال پیگیری است', 'Request approved; wallet credit is being processed', 'تمت الموافقة على الطلب؛ إضافة الرصيد قيد المتابعة')
    : payment?.status === 'pending_review' ? t('پرداخت تأیید شد؛ در انتظار تأیید مدیریت', 'Payment verified; awaiting administrator approval', 'تم التحقق من الدفع؛ بانتظار موافقة المسؤول')
    : payment?.status === 'expired' ? t('مهلت پرداخت پایان یافته است', 'The payment window has expired', 'انتهت مهلة الدفع')
    : payment?.status === 'cancelled' ? t('این درخواست لغو شده است', 'This request was cancelled', 'تم إلغاء هذا الطلب')
    : payment?.status === 'failed' ? t('پرداخت تأیید نشده است', 'The payment was not verified', 'لم يتم تأكيد الدفع')
    : !payment || payment.status === 'creation_unknown' || payment.status === 'created' ? t('در حال پیگیری ثبت درخواست', 'Checking the invoice request', 'جارٍ التحقق من طلب الفاتورة')
    : t('در انتظار واریز شما', 'Awaiting your payment', 'بانتظار إيداعك');

  return <div className="tcartt-deposit" aria-busy={!!busy}>
    <p className="tcartt-intro">{t('مبلغ دقیق و کارت مقصد در صفحه پرداخت تیکارت نمایش داده می‌شود. نتیجه واریز در همین صفحه قابل پیگیری است.', 'Tcartt displays the exact amount and destination card on its payment page. Track your deposit here.', 'يعرض تیکارت المبلغ الدقيق وبطاقة الوجهة في صفحة الدفع. يمكنك متابعة الإيداع هنا.')}</p>
    {!attempt && !payment && <>
      {!props.availability?.ready && <output className="tcartt-state"><Info size={19}/><span>{props.availabilityError || t('اتصال کارت‌به‌کارت تیکارت هنوز فعال نشده است.', 'Tcartt card-to-card payments are not enabled yet.', 'لم يتم تفعيل الدفع عبر تیکارت بعد.')}</span><button type="button" onClick={props.onRefreshAvailability} disabled={!!busy}>{t('بررسی مجدد', 'Retry', 'أعد المحاولة')}</button></output>}
      <button type="button" className="toman-primary" disabled={!restored || !!busy || props.disabled || !props.availability?.ready || !valid} onClick={() => void start()}><CreditCard size={19}/><span>{t('دریافت لینک کارت‌به‌کارت', 'Create card-to-card payment link', 'إنشاء رابط الدفع')}</span><ArrowUpLeft size={18}/></button>
      {!!props.amountToman && !valid && <p className="tcartt-note">{t('حداقل مبلغ کارت‌به‌کارت ۱٬۰۰۰ تومان است.', 'The minimum card-to-card amount is 1,000 TMN.', 'الحد الأدنى للدفع هو ١٬٠٠٠ تومان.')}</p>}
    </>}
    {(attempt || payment) && <>
      <output className={`tcartt-state${paid ? ' is-success' : problem ? ' is-error' : ' is-pending'}`}>{paid ? <CheckCircle2 size={21}/> : problem ? <Info size={21}/> : <Clock3 size={21}/>}<span>{status}</span></output>
      {payment && <dl className="tcartt-amounts"><div><dt>{t('مبلغ درخواستی', 'Requested amount', 'المبلغ المطلوب')}</dt><dd>{money(payment.baseAmountRial)} <small>{currency}</small></dd></div>{invoiceKnown && <div className="tcartt-exact"><dt>{t('مبلغ دقیق واریز', 'Exact payment amount', 'مبلغ الإيداع الدقيق')}</dt><dd>{money(payment.amountRial)} <small>{currency}</small></dd></div>}</dl>}
      {payment && invoiceKnown && payment.amountRial !== payment.baseAmountRial && <p className="tcartt-note">{t('تیکارت برای شناسایی این واریز، چند تومان به مبلغ اضافه کرده است. دقیقاً مبلغ بالا را واریز کنید؛ کل مبلغ واریزی پس از تأیید مدیریت به کیف پول اضافه می‌شود.', 'Tcartt adds a few tomans to identify this payment. Transfer the exact amount above; the full amount will be credited after administrator approval.', 'يضيف تیکارت بضعة تومانات للتعرف على الإيداع. حوّل المبلغ الدقيق أعلاه؛ يُضاف كامل المبلغ بعد موافقة المسؤول.')}</p>}
      {payment?.trackingCode && <div className="tcartt-reference"><span>{t('کد پیگیری', 'Tracking code', 'رمز التتبع')}</span><bdi>{payment.trackingCode}</bdi></div>}
      {pending && payment?.expiresAt && <p className="tcartt-note">{t('مهلت پرداخت:', 'Pay before:', 'مهلة الدفع:')} <time dateTime={payment.expiresAt}>{new Intl.DateTimeFormat(locale, {dateStyle: 'medium', timeStyle: 'short', timeZone: 'Asia/Tehran'}).format(new Date(payment.expiresAt))}</time></p>}
      {pending && payment?.url && payment.status === 'pending' && <a className="toman-primary" href={payment.url} target="_blank" rel="noopener noreferrer">{t('ادامه پرداخت در تیکارت', 'Continue payment on Tcartt', 'متابعة الدفع في تیکارت')}<ArrowUpLeft size={19}/></a>}
      {attempt && !paid && <button type="button" className="toman-submit" disabled={!!busy || props.disabled} onClick={() => void check(attempt)}>{busy ? <LoaderCircle size={18} className="account-spinner"/> : <RefreshCw size={18}/>}<span>{busy ? t('در حال بررسی…', 'Checking…', 'جارٍ التحقق…') : t('بررسی وضعیت همین واریز', 'Check this deposit', 'تحقق من هذا الإيداع')}</span></button>}
      {!payment && canRetry && <button type="button" className="toman-bank-link" disabled={!!busy || props.disabled || !props.availability?.ready} onClick={() => void start()}><RefreshCw size={16}/>{t('تلاش مجدد برای همین درخواست', 'Retry this same request', 'إعادة محاولة الطلب نفسه')}</button>}
      {settled(payment) && <button type="button" className="toman-bank-link" disabled={!!busy || props.disabled} onClick={() => {remember(null); setPayment(null); setError(''); setCanRetry(false); lastState.current = '';}}><Plus size={16}/>{t('درخواست واریز جدید', 'New deposit request', 'طلب إيداع جديد')}</button>}
    </>}
    {error && <p className="toman-alert is-error" role="alert">{error}</p>}
    <p className="tcartt-note tcartt-review-note"><ShieldCheck size={17}/>{t('واریز ابتدا در انتظار بررسی ثبت می‌شود. موجودی فقط پس از تأیید نهایی مدیریت تغییر می‌کند.', 'Deposits remain pending review. Your balance changes only after final administrator approval.', 'يُسجل الإيداع بانتظار المراجعة. يتغير الرصيد بعد موافقة المسؤول النهائية فقط.')}</p>
  </div>;
}
