import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useServerFn } from "@tanstack/react-start";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import {
  customerPortalGetDashboard,
  customerPortalRequestWithdraw,
  customerPortalCheckWithdraw,
  customerPortalUpdateProfile,
  customerPortalChangePassword,
  customerPortalUploadProfileImage,
  customerPortalRemoveProfileImage,
  customerPortalSetReferral,
  customerPortalAddPendingReferral,
  customerPortalDeletePendingReferral,
  customerPortalLookupRecipient,
  customerPortalSendMoney,
} from "@/lib/customer-portal.functions";
import { portalListMyQuotations, portalDeleteQuotation, portalSubmitQuotation } from "@/lib/quotation.functions";
import { QuotationDialog, quotationStatusBadge } from "@/components/portal/QuotationDialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { toast } from "sonner";


import { LogoAnimation } from "@/components/portal/LogoAnimation";
import cashoutIcon from "@/assets/cashout-icon.png";
import purchaseIcon from "@/assets/purchase-icon.png";
import quotationIcon from "@/assets/quotation-icon.png";
import walletHistoryIcon from "@/assets/wallet-history-icon.png";
import addReferralIcon from "@/assets/add-referral-icon.png";
import referralIcon from "@/assets/referral-icon.png";
import profileIcon from "@/assets/profile-icon.png";
import languageIcon from "@/assets/language-icon.png";
import sendMoneyIcon from "@/assets/send-money-icon.png";
import portalLogo from "@/assets/niyamah-logo.png";


import {
  Wallet, WalletCards, LogOut, ShoppingBag, User as UserIcon, KeyRound,
  Camera, Trash2, Plus, UserPlus, FileText, Send, BadgeCheck, AlertTriangle,
  HandCoins, Hourglass, CalendarDays, ChevronDown, Banknote, Languages,
  Eye, EyeOff, Sparkles, Crown, Search, Menu, RefreshCw, Home,
  CheckCircle2, XCircle, ArrowLeft, ArrowRight, Loader2, type LucideIcon,
} from "lucide-react";
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from "@/components/ui/dropdown-menu";
import { useLanguage, type Lang } from "@/hooks/use-language";

export const Route = createFileRoute("/portal/")({
  head: () => ({ meta: [{ title: "My Portal — Niyamah" }] }),
  component: PortalDashboardPage,
});

// ---------- i18n ----------
const S = {
  loading: { bn: "লোড হচ্ছে...", en: "Loading..." },
  logout: { bn: "লগআউট", en: "Logout" },
  active: { bn: "সক্রিয়", en: "Active" },
  inactive: { bn: "নিষ্ক্রিয়", en: "Inactive" },
  totalBalance: { bn: "মোট ব্যালেন্স", en: "Total Balance" },
  customerId: { bn: "Customer ID", en: "Customer ID" },
  email: { bn: "ইমেইল", en: "Email" },
  refMobile: { bn: "রেফারেল মোবাইল", en: "Referral Mobile" },
  address: { bn: "ঠিকানা", en: "Address" },
  lastLogin: { bn: "শেষ লগইন", en: "Last Login" },
  opening: { bn: "ওপেনিং", en: "Opening" },
  purchases: { bn: "কেনাকাটা", en: "Purchases" },
  paid: { bn: "পরিশোধ", en: "Paid" },
  due: { bn: "বকেয়া", en: "Due" },
  walletLabel: { bn: "ওয়ালেট", en: "Wallet" },
  commission: { bn: "কমিশন", en: "Commission" },
  cashOut: { bn: "ক্যাশ আউট", en: "Cash Out" },
  lastPurchase: { bn: "শেষ কেনা", en: "Last Purchase" },
  totalShort: { bn: "মোট", en: "Total" },
  completed: { bn: "সম্পন্ন", en: "Completed" },
  pending: { bn: "পেন্ডিং", en: "Pending" },
  returned: { bn: "ফেরত", en: "Returned" },
  walletEmpty: { bn: "ব্যালেন্স নেই", en: "Empty" },
  quickActions: { bn: "দ্রুত মেনু", en: "Quick Actions" },
  quotation: { bn: "কোটেশন", en: "Quotation" },
  addReferral: { bn: "রেফারেল যোগ", en: "Add Referral" },
  profile: { bn: "প্রোফাইল", en: "Profile" },
  walletHistory: { bn: "ওয়ালেট হিস্ট্রি", en: "Wallet" },
  myQuotations: { bn: "আমার কোটেশন", en: "My Quotations" },
  newQuotation: { bn: "নতুন কোটেশন", en: "New Quote" },
  noQuotations: { bn: "এখনো কোনো কোটেশন তৈরি হয়নি", en: "No quotations yet" },
  forSelf: { bn: "নিজের জন্য", en: "For self" },
  refLabel: { bn: "রেফারেল", en: "Referral" },
  submitted: { bn: "সাবমিট হয়েছে", en: "Submitted" },
  deleted: { bn: "মুছে ফেলা হয়েছে", en: "Deleted" },
  filter: { bn: "ফিল্টার", en: "Filter" },
  clearFilter: { bn: "ফিল্টার মুছুন", en: "Clear" },
  count: { bn: "টি", en: "items" },
  all: { bn: "সকল", en: "All" },
  noPurchases: { bn: "কোনো কেনাকাটা নেই", en: "No purchases yet" },
  dueBadge: { bn: "বকেয়া", en: "Due" },
  noTx: { bn: "কোনো ট্রানজ্যাকশন নেই", en: "No transactions" },
  noCashout: { bn: "কোনো ক্যাশ আউট নেই", en: "No cash out requests" },
  myReferrals: { bn: "আমার রেফারেল", en: "My Referrals" },
  addNumber: { bn: "নতুন নাম্বার", en: "Add Number" },
  waiting: { bn: "অপেক্ষমান", en: "Pending" },
  noWaiting: { bn: "কোনো অপেক্ষমান নাম্বার নেই", en: "No pending numbers" },
  added: { bn: "যোগ", en: "Added" },
  joined: { bn: "যুক্ত হয়েছে", en: "Joined" },
  noOneJoined: { bn: "এখনো কেউ যুক্ত হয়নি", en: "Nobody joined yet" },
  name: { bn: "নাম", en: "Name" },
  mobile: { bn: "মোবাইল", en: "Mobile" },
  date: { bn: "তারিখ", en: "Date" },
  addRefTitle: { bn: "নতুন রেফারেল নাম্বার যোগ করুন", en: "Add referral number" },
  mobileRequired: { bn: "মোবাইল নাম্বার *", en: "Mobile Number *" },
  mobilePh: { bn: "01XXXXXXXXX", en: "01XXXXXXXXX" },
  refHint: { bn: "এই নাম্বারের কাস্টমার রেজিস্টার করলেই সরাসরি আপনার নামে যুক্ত হবে।", en: "When that customer registers, they will be linked to you." },
  noteOpt: { bn: "নোট (ঐচ্ছিক)", en: "Note (optional)" },
  notePh: { bn: "নাম বা মন্তব্য", en: "Name or comment" },
  cancel: { bn: "বাতিল", en: "Cancel" },
  add: { bn: "যোগ করুন", en: "Add" },
  validMobile: { bn: "সঠিক মোবাইল দিন", en: "Enter a valid mobile" },
  addedSuccess: { bn: "রেফারেল নাম্বার যোগ হয়েছে", en: "Referral added" },
  linkedDirect: { bn: "ঐ কাস্টমার রেজিস্টার্ড — সরাসরি লিঙ্ক হয়েছে", en: "Linked directly" },
  addFail: { bn: "যোগ করা যায়নি", en: "Could not add" },
  delFail: { bn: "মোছা যায়নি", en: "Could not delete" },
  cashoutTitle: { bn: "ক্যাশ আউট রিকোয়েস্ট", en: "Cash Out Request" },
  availableBalance: { bn: "উপলব্ধ:", en: "Available:" },
  amount: { bn: "পরিমাণ *", en: "Amount *" },
  method: { bn: "মাধ্যম *", en: "Method *" },
  accountNo: { bn: "অ্যাকাউন্ট নম্বর *", en: "Account Number *" },
  note: { bn: "নোট", en: "Note" },
  submit: { bn: "জমা দিন", en: "Submit" },
  reqAmount: { bn: "সঠিক পরিমাণ দিন", en: "Enter a valid amount" },
  insufficient: { bn: "ব্যালেন্স অপর্যাপ্ত", en: "Insufficient balance" },
  needAcc: { bn: "অ্যাকাউন্ট নম্বর লাগবে", en: "Account number required" },
  reqSubmitted: { bn: "রিকোয়েস্ট জমা হয়েছে", en: "Request submitted" },
  minAmount: { bn: "সর্বনিম্ন ৳৫০", en: "Minimum ৳50" },
  maxAmount: { bn: "সর্বোচ্চ ব্যালেন্সের সমান", en: "Cannot exceed balance" },
  wholeOnly: { bn: "শুধু পূর্ণসংখ্যা টাকা", en: "Whole taka only" },
  mfsBadMobile: { bn: "১১ ডিজিটের সঠিক মোবাইল নম্বর দিন (০১...)", en: "Enter a valid 11-digit mobile (01...)" },
  bankAccShort: { bn: "অ্যাকাউন্ট নম্বর কমপক্ষে ৬ অক্ষর", en: "Account number must be at least 6 chars" },
  bankAccLong: { bn: "অ্যাকাউন্ট নম্বর সর্বোচ্চ ২০ অক্ষর", en: "Account number must be at most 20 chars" },
  bankAccBadChars: { bn: "শুধু অক্ষর/সংখ্যা ব্যবহার করুন", en: "Use letters and digits only" },
  reviewTitle: { bn: "তথ্য যাচাই করুন", en: "Review your request" },
  back: { bn: "পিছনে", en: "Back" },
  confirm: { bn: "নিশ্চিত করুন", en: "Confirm" },
  next: { bn: "পরবর্তী", en: "Next" },
  grossAmount: { bn: "ব্যালেন্স থেকে কাটা হবে", en: "Deducted from balance" },
  netAmount: { bn: "আপনি পাবেন", en: "You receive" },
  fee: { bn: "ক্যাশআউট চার্জ", en: "Cashout fee" },
  feeRate: { bn: "চার্জের হার", en: "Fee rate" },
  feeNote: { bn: "চার্জ সরবরাহকারীর প্রকাশিত হারের ভিত্তিতে আনুমানিক; প্রকৃত হিসাব ভিন্ন হতে পারে।", en: "Fee is an estimate based on the provider's published rate; actual charge may vary." },
  successTitle: { bn: "রিকোয়েস্ট সফলভাবে জমা হয়েছে", en: "Request submitted successfully" },
  successDesc: { bn: "অনুমোদনের পর টাকা আপনার অ্যাকাউন্টে পাঠানো হবে।", en: "Funds will be sent after approval." },
  pendingTitle: { bn: "অনুমোদনের অপেক্ষায়…", en: "Awaiting approval…" },
  pendingDesc: { bn: "অ্যাডমিন অনুমোদন/প্রত্যাখ্যান করলে এখানে স্বয়ংক্রিয়ভাবে আপডেট হবে।", en: "This will update automatically once an admin approves or rejects." },
  approvedTitle: { bn: "অনুমোদিত হয়েছে!", en: "Approved!" },
  approvedDesc: { bn: "টাকা আপনার অ্যাকাউন্টে পাঠানো হচ্ছে।", en: "Funds are being sent to your account." },
  rejectedTitle: { bn: "প্রত্যাখ্যাত হয়েছে", en: "Request rejected" },
  rejectedDesc: { bn: "অ্যাডমিন নোট", en: "Admin note" },
  closeKeepOpen: { bn: "ব্যাকগ্রাউন্ডে রাখুন", en: "Keep waiting" },
  failTitle: { bn: "রিকোয়েস্ট ব্যর্থ হয়েছে", en: "Request failed" },
  retry: { bn: "আবার চেষ্টা করুন", en: "Retry" },
  done: { bn: "সম্পন্ন", en: "Done" },
  quickAmount: { bn: "দ্রুত নির্বাচন", en: "Quick pick" },
  max: { bn: "MAX", en: "MAX" },
  remaining: { bn: "অবশিষ্ট থাকবে", en: "Remaining after" },
  noBalance: { bn: "ক্যাশ আউটের জন্য পর্যাপ্ত ব্যালেন্স নেই", en: "Not enough balance to cash out" },
  profileImage: { bn: "প্রোফাইল ছবি", en: "Profile Image" },
  change: { bn: "পরিবর্তন", en: "Change" },
  remove: { bn: "সরান", en: "Remove" },
  removed: { bn: "সরানো হয়েছে", en: "Removed" },
  imgOnly: { bn: "শুধু JPG/PNG/WebP", en: "JPG/PNG/WebP only" },
  imgMax: { bn: "সর্বোচ্চ 5MB", en: "Max 5MB" },
  imgUpdated: { bn: "ছবি আপডেট হয়েছে", en: "Image updated" },
  uploadFail: { bn: "আপলোড ব্যর্থ", en: "Upload failed" },
  personalInfo: { bn: "ব্যক্তিগত তথ্য", en: "Personal Info" },
  nameEn: { bn: "নাম (English) *", en: "Name (English) *" },
  nameBn: { bn: "নাম (বাংলা)", en: "Name (Bengali)" },
  mobileNo: { bn: "মোবাইল নম্বর", en: "Mobile Number" },
  mobileChangeHint: { bn: "পরিবর্তনের জন্য অ্যাডমিনের সাথে যোগাযোগ করুন", en: "Contact admin to change" },
  customerType: { bn: "কাস্টমার টাইপ", en: "Customer Type" },
  save: { bn: "সংরক্ষণ", en: "Save" },
  saveFail: { bn: "সংরক্ষণ ব্যর্থ", en: "Save failed" },
  nameNeeded: { bn: "নাম লাগবে", en: "Name is required" },
  profileUpdated: { bn: "প্রোফাইল আপডেট হয়েছে", en: "Profile updated" },
  changePassword: { bn: "পাসওয়ার্ড পরিবর্তন", en: "Change Password" },
  currentPw: { bn: "বর্তমান পাসওয়ার্ড", en: "Current Password" },
  newPw: { bn: "নতুন পাসওয়ার্ড", en: "New Password" },
  confirmPw: { bn: "নিশ্চিত করুন", en: "Confirm" },
  changeBtn: { bn: "পরিবর্তন করুন", en: "Change" },
  pwShort: { bn: "নতুন পাসওয়ার্ড কমপক্ষে ৪ অক্ষর", en: "New password must be at least 4 characters" },
  pwMismatch: { bn: "পাসওয়ার্ড মিলছে না", en: "Passwords do not match" },
  pwChanged: { bn: "পাসওয়ার্ড পরিবর্তন হয়েছে", en: "Password changed" },
  failed: { bn: "ব্যর্থ", en: "Failed" },
  refSetHint: { bn: "রেফারেল মোবাইল নাম্বার (যিনি আপনাকে রেফার করেছেন)", en: "Referrer mobile number" },
  set: { bn: "সেট করুন", en: "Set" },
  verifying: { bn: "যাচাই...", en: "Verifying..." },
  refSetWarn: { bn: "একবার সেট করার পরে এটি স্থায়ী হবে।", en: "Once set, this is permanent." },
  refIsSet: { bn: "রেফারেল সেট আছে:", en: "Referral set:" },
  refContactAdmin: { bn: "(পরিবর্তনের জন্য অ্যাডমিনের সাথে যোগাযোগ করুন)", en: "(contact admin to change)" },
  noMobile: { bn: "মোবাইল নাম্বার দিন", en: "Enter mobile number" },
  noSelfRef: { bn: "নিজের নাম্বার দেওয়া যাবে না", en: "Cannot reference your own number" },
  refLinked: { bn: "রেফারেল যুক্ত হয়েছে:", en: "Referral linked:" },
  segVip: { bn: "VIP", en: "VIP" },
  segRegular: { bn: "নিয়মিত", en: "Regular" },
  segNew: { bn: "নতুন", en: "New" },
  segInactive: { bn: "নিষ্ক্রিয়", en: "Inactive" },
  totalEarn: { bn: "মোট আয়", en: "Total Earnings" },
  totalCashout: { bn: "মোট ক্যাশ আউট", en: "Total Cash Out" },
  paidSuffix: { bn: "পরিশোধিত", en: "paid" },
  payNow: { bn: "পরিশোধ করুন", en: "Pay Now" },
  noDue: { bn: "কোনো বকেয়া নেই", en: "All clear" },
  welcomeBack: { bn: "স্বাগতম", en: "Welcome back" },
  sendMoney: { bn: "সেন্ড মানি", en: "Send Money" },
  sendMoneyTitle: { bn: "অন্য কাস্টমারকে টাকা পাঠান", en: "Send money to another customer" },
  recipientMobile: { bn: "রিসিপিয়েন্ট মোবাইল *", en: "Recipient Mobile *" },
  searchRecipient: { bn: "খুঁজুন", en: "Search" },
  recipientFound: { bn: "রিসিপিয়েন্ট", en: "Recipient" },
  notFound: { bn: "এই নাম্বারে কাস্টমার পাওয়া যায়নি", en: "No customer found with this number" },
  sendAmount: { bn: "পরিমাণ (৳) *", en: "Amount (৳) *" },
  sendNote: { bn: "নোট (ঐচ্ছিক)", en: "Note (optional)" },
  reviewSend: { bn: "যাচাই করুন", en: "Review" },
  confirmSend: { bn: "পাঠিয়ে দিন", en: "Send Now" },
  sendSuccess: { bn: "টাকা পাঠানো হয়েছে", en: "Money sent successfully" },
  sendFail: { bn: "পাঠানো ব্যর্থ", en: "Send failed" },
  newBalance: { bn: "নতুন ব্যালেন্স", en: "New balance" },
  txnRef: { bn: "রেফারেন্স", en: "Reference" },
} as const;

type SKey = keyof typeof S;
type TFn = (k: SKey) => string;

function useT() {
  const { lang, toggleLang } = useLanguage();
  const T: TFn = (k) => S[k]?.[lang] ?? S[k]?.bn ?? String(k);
  return { T, lang, toggleLang };
}

// ============ Main Page ============
function PortalDashboardPage() {
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const { T, lang, toggleLang } = useT();
  const [token, setToken] = useState<string | null>(null);
  const [withdrawOpen, setWithdrawOpen] = useState(false);
  const [addRefOpen, setAddRefOpen] = useState(false);
  const [newRefMobile, setNewRefMobile] = useState("");
  const [newRefNote, setNewRefNote] = useState("");
  const [quoteOpen, setQuoteOpen] = useState(false);
  const [showBalance, setShowBalance] = useState(false);
  const [splash, setSplash] = useState(true);
  const [activeTab, setActiveTab] = useState<string>("");
  const [menuOpen, setMenuOpen] = useState(false);
  const [salesFilter, setSalesFilter] = useState<"all" | "completed" | "pending" | "returned">("all");
  const [sendOpen, setSendOpen] = useState(false);

  useEffect(() => {
    const t = setTimeout(() => setSplash(false), 1600);
    return () => clearTimeout(t);
  }, []);

  useEffect(() => {
    const t = typeof window !== "undefined" ? localStorage.getItem("customer_portal_token") : null;
    if (!t) navigate({ to: "/portal/login", search: { mobile: "" } });
    else setToken(t);
  }, [navigate]);

  const getDash = useServerFn(customerPortalGetDashboard);
  const reqWithdraw = useServerFn(customerPortalRequestWithdraw);
  const checkWithdraw = useServerFn(customerPortalCheckWithdraw);
  const addPendingRef = useServerFn(customerPortalAddPendingReferral);
  const delPendingRef = useServerFn(customerPortalDeletePendingReferral);
  const listMyQuotesFn = useServerFn(portalListMyQuotations);
  const delQuoteFn = useServerFn(portalDeleteQuotation);
  const submitQuoteFn = useServerFn(portalSubmitQuotation);
  const lookupRecipientFn = useServerFn(customerPortalLookupRecipient);
  const sendMoneyFn = useServerFn(customerPortalSendMoney);

  const { data, isLoading, refetch, error: dashError } = useQuery({
    queryKey: ["portal-dashboard", token],
    enabled: !!token,
    queryFn: () => getDash({ data: { token: token! } }),
    retry: false,
  });

  const { data: myQuotes = [], refetch: refetchQuotes, error: quotesError } = useQuery({
    queryKey: ["portal-quotations", token],
    enabled: !!token,
    queryFn: () => listMyQuotesFn({ data: { token: token! } }),
    retry: false,
  });

  const isAuthErr = (msg?: string) =>
    !!msg && /JWT|exp.*claim|Invalid token|Invalid portal session|Portal session expired|Unauthorized|expired/i.test(msg);

  useEffect(() => {
    const errMsg = (dashError as any)?.message || (quotesError as any)?.message;
    if ((data as any)?.error || isAuthErr(errMsg)) {
      localStorage.removeItem("customer_portal_token");
      localStorage.removeItem("customer_portal_customer");
      navigate({ to: "/portal/login", search: { mobile: "" } });
    }
  }, [data, dashError, quotesError, navigate]);

  const addRefMut = useMutation({
    mutationFn: (vars: { mobile: string; note: string }) => addPendingRef({ data: { token: token!, mobile: vars.mobile, note: vars.note } }),
    onSuccess: (res: any) => {
      toast.success(res?.linked_directly ? T("linkedDirect") : T("addedSuccess"));
      setAddRefOpen(false); setNewRefMobile(""); setNewRefNote("");
      refetch();
    },
    onError: (e: any) => toast.error(e?.message || T("addFail")),
  });

  const delRefMut = useMutation({
    mutationFn: (id: string) => delPendingRef({ data: { token: token!, id } }),
    onSuccess: () => { toast.success(T("deleted")); refetch(); },
    onError: (e: any) => toast.error(e?.message || T("delFail")),
  });

  const logout = () => {
    localStorage.removeItem("customer_portal_token");
    localStorage.removeItem("customer_portal_customer");
    navigate({ to: "/portal/login", search: { mobile: "" } });
  };

  // Auto-logout after 5 minutes of inactivity
  useEffect(() => {
    if (!token) return;
    const IDLE_MS = 5 * 60 * 1000;
    let timer: ReturnType<typeof setTimeout>;
    const doLogout = () => {
      localStorage.removeItem("customer_portal_token");
      localStorage.removeItem("customer_portal_customer");
      toast.info(lang === "bn" ? "নিষ্ক্রিয়তার কারণে অটো লগআউট" : "Auto logged out due to inactivity");
      navigate({ to: "/portal/login", search: { mobile: "" } });
    };
    const reset = () => {
      clearTimeout(timer);
      timer = setTimeout(doLogout, IDLE_MS);
    };
    const events = ["mousemove", "mousedown", "keydown", "touchstart", "scroll", "click"] as const;
    events.forEach((e) => window.addEventListener(e, reset, { passive: true }));
    reset();
    return () => {
      clearTimeout(timer);
      events.forEach((e) => window.removeEventListener(e, reset));
    };
  }, [token, navigate, lang]);


  const scrollToTab = (tab: string) => {
    const isSame = activeTab === tab;
    // Toggle: tapping the active item again hides it back into the menu
    setActiveTab(isSame ? "" : tab);
    setMenuOpen(false);
    if (isSame) return;
    // Wait for Sheet close animation + Radix scroll-lock release before scrolling
    const doScroll = () => {
      const el = document.getElementById("portal-tabs");
      if (!el) return;
      const headerOffset = 64;
      const y = el.getBoundingClientRect().top + window.scrollY - headerOffset;
      window.scrollTo({ top: y, behavior: "smooth" });
    };
    setTimeout(doScroll, 350);
  };

  if (!token || isLoading) {
    return (
      <div className="min-h-screen bg-white text-slate-900">
        <LogoAnimation duration={10000} />
      </div>
    );
  }


  const customer = (data as any)?.customer;
  const wallet = (data as any)?.wallet;
  const walletTx = (data as any)?.walletTx || [];
  const sales = (data as any)?.sales || [];
  const withdrawals = (data as any)?.withdrawals || [];
  const referrals = (data as any)?.referrals || [];
  const pendingReferrals = (data as any)?.pendingReferrals || [];
  const summary = (data as any)?.summary || {};
  const balance = Number(wallet?.balance || 0);
  const totalDue = Number(customer?.total_due || 0);
  const fmt = (n: number) => `৳${Number(n || 0).toLocaleString(lang === "en" ? "en-US" : "en-IN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
  const fmtDate = (d: string | null) => d ? new Date(d).toLocaleDateString(lang === "en" ? "en-US" : "en-GB") : "—";
  const displayName = (lang === "en" ? (customer?.name || customer?.name_bn) : (customer?.name_bn || customer?.name)) || "";
  const segMeta: Record<string, { label: string; cls: string; icon: LucideIcon }> = {
    vip:      { label: T("segVip"),      cls: "bg-amber-500/15 text-amber-700 border-amber-500/30",   icon: Crown },
    regular:  { label: T("segRegular"),  cls: "bg-violet-500/15 text-violet-700 border-violet-500/30", icon: BadgeCheck },
    new:      { label: T("segNew"),      cls: "bg-emerald-500/15 text-emerald-700 border-emerald-500/30", icon: Sparkles },
    inactive: { label: T("segInactive"), cls: "bg-slate-700/40 text-slate-600 border-slate-600/40",    icon: Hourglass },
  };
  const seg = segMeta[(summary.segment as string) || "new"];
  const SegIcon = seg.icon;

  return (
    <div className="min-h-screen bg-white text-slate-900">
      {/* Splash */}
      {splash && (
        <div className="fixed inset-0 z-[100] flex items-center justify-center bg-white" style={{ animation: "splashFade 1.6s ease forwards" }}>
          <style>{`
            @keyframes splashFade { 0%,70%{opacity:1} 100%{opacity:0; visibility:hidden} }
            @keyframes logoPop { 0%{transform:scale(.6); opacity:0} 60%{transform:scale(1.1)} 100%{transform:scale(1); opacity:1} }
            @keyframes ringGlow { 0%,100%{transform:scale(1); opacity:.6} 50%{transform:scale(1.15); opacity:.2} }
          `}</style>
          <div className="relative">
            <span className="absolute inset-0 rounded-full bg-violet-500/40 blur-2xl" style={{ animation: "ringGlow 1.4s ease-in-out infinite" }} />
            <span className="absolute -inset-3 rounded-full border-2 border-violet-400/30" style={{ animation: "ringGlow 2s ease-in-out infinite" }} />
            <div className="relative h-28 w-28 rounded-full bg-white grid place-items-center shadow-2xl shadow-violet-500/50 ring-4 ring-violet-400/40 overflow-hidden" style={{ animation: "logoPop .7s cubic-bezier(.34,1.56,.64,1) both" }}>
              <img src={portalLogo} alt="Niyamah" className="h-full w-full object-contain p-1" />
            </div>
          </div>
        </div>
      )}

      {/* bKash-style pink landscape hero */}
      <header className="relative overflow-hidden">
        <style>{`
          @keyframes bkSunPulse { 0%,100% { transform: scale(1); opacity: .85 } 50% { transform: scale(1.08); opacity: 1 } }
          @keyframes bkSunGlow  { 0%,100% { transform: scale(1); opacity: .5 }  50% { transform: scale(1.25); opacity: .15 } }
          @keyframes bkCloudA   { 0% { transform: translateX(-10%) } 100% { transform: translateX(110%) } }
          @keyframes bkCloudB   { 0% { transform: translateX(110%) } 100% { transform: translateX(-20%) } }
          @keyframes bkRiver    { 0%,100% { opacity: .55 } 50% { opacity: .8 } }
        `}</style>

        {/* Pink gradient sky */}
        <div className="absolute inset-0 pointer-events-none bg-gradient-to-b from-[#6d28d9] via-[#5b21b6] to-[#3b0d80]" />

        {/* Pulsing sun */}
        <div className="absolute right-10 top-16 pointer-events-none">
          <div className="relative h-24 w-24">
            <span className="absolute inset-0 rounded-full bg-violet-200/70 blur-2xl" style={{ animation: "bkSunGlow 3s ease-in-out infinite" }} />
            <span className="absolute inset-2 rounded-full bg-gradient-to-br from-violet-100 to-violet-300 shadow-2xl shadow-violet-200/40" style={{ animation: "bkSunPulse 3s ease-in-out infinite" }} />
          </div>
        </div>

        {/* Floating clouds */}
        <svg className="absolute top-4 left-0 w-full h-12 pointer-events-none opacity-80" viewBox="0 0 400 60" fill="none" preserveAspectRatio="none">
          <g style={{ animation: "bkCloudA 28s linear infinite" }}>
            <ellipse cx="40" cy="30" rx="28" ry="9" fill="#ede9fe" opacity=".55" />
            <ellipse cx="60" cy="24" rx="18" ry="7" fill="#ede9fe" opacity=".7" />
          </g>
        </svg>
        <svg className="absolute top-12 left-0 w-full h-10 pointer-events-none opacity-70" viewBox="0 0 400 60" fill="none" preserveAspectRatio="none">
          <g style={{ animation: "bkCloudB 36s linear infinite" }}>
            <ellipse cx="80" cy="30" rx="32" ry="8" fill="#ddd6fe" opacity=".6" />
            <ellipse cx="105" cy="25" rx="16" ry="6" fill="#ddd6fe" opacity=".75" />
          </g>
        </svg>

        {/* Landscape — mountains, river, houses, trees */}
        <svg className="absolute bottom-0 left-0 w-full pointer-events-none" viewBox="0 0 400 130" preserveAspectRatio="none" fill="none">
          <path d="M0 95 L60 55 L120 85 L180 45 L240 80 L320 50 L400 90 L400 130 L0 130 Z" fill="#5b21b6" opacity=".55" />
          <path d="M0 110 L50 80 L110 100 L170 70 L230 95 L300 75 L400 105 L400 130 L0 130 Z" fill="#4c1d95" opacity=".75" />
          <path d="M0 118 Q100 108 200 116 T400 112 L400 130 L0 130 Z" fill="#c4b5fd" opacity=".6" style={{ animation: "bkRiver 4s ease-in-out infinite" }} />
          <path d="M0 120 L400 120 L400 130 L0 130 Z" fill="#3b0d80" opacity=".7" />
          <g opacity=".85">
            <rect x="48" y="108" width="2.5" height="10" fill="#2e0a66" />
            <circle cx="49" cy="106" r="6" fill="#2e0a66" />
          </g>
          <g opacity=".9">
            <rect x="160" y="108" width="14" height="11" fill="#ede9fe" />
            <path d="M158 108 L167 100 L176 108 Z" fill="#3b0d80" />
            <rect x="165" y="113" width="4" height="6" fill="#3b0d80" />
          </g>
          <g opacity=".85">
            <rect x="310" y="105" width="3" height="14" fill="#2e0a66" />
            <circle cx="311.5" cy="103" r="7" fill="#2e0a66" />
          </g>
          <g opacity=".85">
            <rect x="350" y="111" width="11" height="9" fill="#ede9fe" />
            <path d="M348 111 L355.5 105 L363 111 Z" fill="#3b0d80" />
          </g>
        </svg>

        <div className="relative max-w-5xl mx-auto px-4 pt-6 pb-20">
          <div className="flex items-start justify-between gap-3">
            <div className="flex items-center gap-2 min-w-0 flex-1">
              {/* Hamburger menu — opens left drawer with stats */}
              <Sheet open={menuOpen} onOpenChange={setMenuOpen}>
                <SheetTrigger asChild>
                  <button
                    title={lang === "bn" ? "মেনু" : "Menu"}
                    aria-label={lang === "bn" ? "মেনু" : "Menu"}
                    className="h-12 w-12 rounded-2xl bg-white/15 ring-1 ring-white/30 grid place-items-center text-white hover:bg-white/25 active:scale-90 transition-all duration-200 shrink-0 touch-manipulation"
                  >
                    <Menu className="h-6 w-6" />
                  </button>
                </SheetTrigger>
                <SheetContent
                  side="left"
                  className="w-[92%] sm:w-96 bg-white text-slate-900 border-slate-200 overflow-y-auto p-5 data-[state=open]:duration-300 data-[state=closed]:duration-200"
                >
                  <SheetHeader>
                    <div className="flex items-center justify-between gap-2">
                      <SheetTitle className="text-slate-900 flex items-center gap-2 text-base">
                        <Wallet className="h-5 w-5 text-violet-600" />
                        {T("totalShort")} & {T("purchases")}
                      </SheetTitle>
                      <button
                        onClick={async () => {
                          try {
                            await Promise.all([refetch(), refetchQuotes()]);
                            toast.success(lang === "bn" ? "রিফ্রেশ হয়েছে" : "Refreshed");
                          } catch {
                            toast.error(lang === "bn" ? "রিফ্রেশ ব্যর্থ" : "Refresh failed");
                          }
                        }}
                        title={lang === "bn" ? "রিফ্রেশ" : "Refresh"}
                        aria-label={lang === "bn" ? "রিফ্রেশ" : "Refresh"}
                        className="mr-8 h-10 w-10 rounded-xl bg-slate-100 ring-1 ring-slate-200 grid place-items-center text-slate-700 hover:bg-slate-200 active:scale-90 transition touch-manipulation"
                      >
                        <RefreshCw className={`h-4 w-4 ${isLoading ? "animate-spin" : ""}`} />
                      </button>
                    </div>
                  </SheetHeader>

                  {/* Navigation */}
                  <div className="mt-6">
                    <div className="text-[11px] text-slate-500 uppercase tracking-wider mb-2.5 px-1">{lang === "bn" ? "মেনু" : "Menu"}</div>
                    <div className="grid grid-cols-2 gap-2.5">
                      {[
                        { v: "purchases",   label: T("purchases") },
                        { v: "quotations",  label: `${T("quotation")} (${myQuotes.length})` },
                        { v: "wallet",      label: T("walletHistory") },
                        { v: "withdrawals", label: T("cashOut") },
                        { v: "referrals",   label: `${T("refLabel")} (${referrals.length + pendingReferrals.length})` },
                        { v: "profile",     label: T("profile") },
                      ].map((it) => (
                        <button
                          key={it.v}
                          onClick={() => scrollToTab(it.v)}
                          className={`text-sm rounded-xl px-3.5 py-3.5 min-h-12 border text-left transition-all active:scale-[0.97] touch-manipulation ${
                            activeTab === it.v
                              ? "bg-violet-100 text-violet-700 border-violet-300"
                              : "bg-slate-50 text-slate-800 border-slate-200 hover:bg-slate-100"
                          }`}
                        >
                          {it.label}
                        </button>
                      ))}
                    </div>
                  </div>




                  {/* Account summary */}
                  <div className="mt-5">
                    <div className="text-[11px] text-slate-500 uppercase tracking-wider mb-2 px-1">{T("totalShort")}</div>
                    <div className="grid grid-cols-2 gap-2">
                      <StatCard label={T("opening")}     value={fmt(customer?.opening_balance)} tone="slate" />
                      <StatCard label={T("purchases")}   value={fmt(summary.totalPurchase)}    tone="violet" />
                      <StatCard label={T("paid")}        value={fmt(summary.totalPaid)}        tone="emerald" />
                      <StatCard label={T("due")}         value={fmt(totalDue)}                 tone={totalDue > 0 ? "rose" : "slate"} />
                      <StatCard label={T("walletLabel")} value={fmt(balance)}                  tone="violet" />
                      <StatCard label={T("commission")}  value={fmt(wallet?.total_commission)} tone="amber" />
                      <StatCard label={T("cashOut")}     value={fmt(summary.withdrawPending)}  tone={summary.withdrawPending > 0 ? "amber" : "slate"} />
                      <StatCard label={T("lastPurchase")} value={fmtDate(summary.lastPurchaseDate)} tone="cyan" small />
                    </div>
                  </div>

                  {/* Purchase filter pills */}
                  <div className="mt-5">
                    <div className="text-[11px] text-slate-500 uppercase tracking-wider mb-2 px-1">{T("purchases")}</div>
                    <div className="grid grid-cols-2 gap-2">
                      <MiniStat label={T("all")}       value={summary.totalOrders || 0}    tone="violet"  active={salesFilter === "all"}       onClick={() => { setSalesFilter("all"); scrollToTab("purchases"); }} />
                      <MiniStat label={T("completed")} value={summary.completedOrders || 0} tone="emerald" active={salesFilter === "completed"} onClick={() => { setSalesFilter("completed"); scrollToTab("purchases"); }} />
                      <MiniStat label={T("pending")}   value={summary.pendingOrders || 0}   tone="amber"   active={salesFilter === "pending"}   onClick={() => { setSalesFilter("pending"); scrollToTab("purchases"); }} />
                      <MiniStat label={T("returned")}  value={summary.returnedOrders || 0}  tone="rose"    active={salesFilter === "returned"}  onClick={() => { setSalesFilter("returned"); scrollToTab("purchases"); }} />

                    </div>
                  </div>
                </SheetContent>
              </Sheet>

              <Avatar className="h-12 w-12 ring-2 ring-white/60 shadow-xl shadow-violet-900/40 shrink-0">
                <AvatarImage src={customer?.image_url || undefined} />
                <AvatarFallback className="bg-gradient-to-br from-violet-500 to-violet-600 text-white font-bold">
                  {(displayName || "?").slice(0, 1)}
                </AvatarFallback>
              </Avatar>
              <div className="min-w-0 flex-1">
                <div className="font-bold text-base text-white truncate flex items-center gap-2 drop-shadow-sm">
                  {displayName}
                  <span className={`inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[9px] font-semibold ${seg.cls}`}>
                    <SegIcon className="h-2.5 w-2.5" />
                    {seg.label}
                  </span>
                </div>
                <button
                  onClick={() => setShowBalance((v) => !v)}
                  className="mt-1.5 inline-flex items-center gap-2 rounded-full bg-white pl-1 pr-4 py-1 text-[12px] font-semibold text-slate-800 shadow-lg shadow-violet-900/30 hover:bg-slate-50 active:scale-[0.98] transition"
                >
                  <span className="grid place-items-center h-6 w-6 rounded-full bg-gradient-to-br from-violet-500 to-violet-600 text-white font-bold text-[13px] shadow-inner">৳</span>
                  {showBalance ? (
                    <span className="tabular-nums text-violet-700 font-bold">
                      ৳{Number(balance).toLocaleString(lang === "en" ? "en-US" : "en-IN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
                    </span>
                  ) : (
                    <span>{lang === "bn" ? "ব্যালেন্স দেখুন" : "See Balance"}</span>
                  )}
                </button>
              </div>
            </div>

            <div className="flex items-center gap-2 shrink-0">
              <button
                onClick={logout}
                title={T("logout")}
                aria-label={T("logout")}
                className="h-12 w-12 rounded-2xl bg-white/15 ring-1 ring-white/30 grid place-items-center text-white hover:bg-white/25 active:scale-90 transition-all duration-200 shrink-0 touch-manipulation"
              >
                <LogOut className="h-5 w-5" />
              </button>
            </div>

          </div>
        </div>
      </header>

      <main className="relative max-w-5xl mx-auto px-3 sm:px-4 mt-2 pb-10 space-y-4">
        {/* Balance card — shown when "ব্যালেন্স দেখুন" pill is tapped */}
        {showBalance && (
          <div className="rounded-3xl bg-gradient-to-br from-violet-600 via-violet-600 to-fuchsia-600 p-[1px] shadow-2xl shadow-violet-900/40 animate-in fade-in slide-in-from-top-2 duration-300">
            <div className="rounded-3xl bg-slate-900/80 backdrop-blur-xl px-5 py-5 sm:px-6 sm:py-6">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-2 text-slate-600 text-xs">
                  <Wallet className="h-3.5 w-3.5" />
                  {T("totalBalance")}
                </div>
                <button onClick={() => setShowBalance(false)} className="h-7 w-7 grid place-items-center rounded-full bg-slate-50 ring-1 ring-slate-200 text-slate-700 hover:bg-slate-100 transition" title="Hide">
                  <EyeOff className="h-3.5 w-3.5" />
                </button>
              </div>
              <div className="mt-2 flex items-baseline gap-1">
                <span className="text-slate-500 text-2xl font-light">৳</span>
                <span className="text-4xl sm:text-5xl font-extrabold tracking-tight tabular-nums bg-gradient-to-r from-white to-slate-300 bg-clip-text text-transparent">
                  {Number(balance).toLocaleString(lang === "en" ? "en-US" : "en-IN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
                </span>
              </div>
              <div className="mt-3 grid grid-cols-3 gap-2">
                <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 px-3 py-2">
                  <div className="text-[9px] text-slate-600 uppercase tracking-wider">{T("totalEarn")}</div>
                  <div className="text-sm font-bold text-emerald-700 truncate">{fmt(wallet?.total_commission)}</div>
                </div>
                <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 px-3 py-2">
                  <div className="text-[9px] text-slate-600 uppercase tracking-wider">{T("totalCashout")}</div>
                  <div className="text-sm font-bold text-violet-700 truncate">{fmt(summary.totalWithdraw)}</div>
                </div>
                <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 px-3 py-2">
                  <div className="text-[9px] text-slate-600 uppercase tracking-wider">{T("pending")}</div>
                  <div className="text-sm font-bold text-amber-700 truncate">{fmt(summary.withdrawPending)}</div>
                </div>
              </div>
              <Button
                onClick={() => setWithdrawOpen(true)}
                disabled={balance <= 0}
                className="mt-4 w-full h-11 rounded-xl bg-white text-slate-900 hover:bg-slate-100 font-bold shadow-lg disabled:opacity-40"
              >
                <Banknote className="h-4 w-4 mr-2" />
                {T("cashOut")}
              </Button>
            </div>
          </div>
        )}


        {/* Quick Actions */}
        <section className="rounded-2xl bg-white border border-slate-200 overflow-hidden shadow-lg shadow-slate-200/50">


          <div className="grid grid-cols-4 gap-2 p-3">
            <MenuTile label={T("sendMoney")} icon={Send} tone="indigo" imgSrc={sendMoneyIcon} onClick={() => setSendOpen(true)} />
            <MenuTile label={T("cashOut")} icon={Banknote} tone="violet" imgSrc={cashoutIcon} onClick={() => setWithdrawOpen(true)} />
            <MenuTile label={T("purchases")} icon={ShoppingBag} tone="emerald" imgSrc={purchaseIcon} onClick={() => scrollToTab("purchases")} />
            <MenuTile label={T("quotation")} icon={FileText} tone="violet" imgSrc={quotationIcon} onClick={() => setQuoteOpen(true)} />
            <MenuTile label={T("walletHistory")} icon={WalletCards} tone="fuchsia" imgSrc={walletHistoryIcon} onClick={() => scrollToTab("wallet")} />
            <MenuTile label={T("addReferral")} icon={UserPlus} tone="amber" imgSrc={addReferralIcon} onClick={() => setAddRefOpen(true)} />
            <MenuTile label={T("refLabel")} icon={Crown} tone="rose" imgSrc={referralIcon} onClick={() => scrollToTab("referrals")} />
            <MenuTile label={T("profile")} icon={UserIcon} tone="cyan" imgSrc={profileIcon} onClick={() => scrollToTab("profile")} />
            <MenuTile label={lang === "bn" ? "English" : "বাংলা"} icon={Languages} tone="slate" imgSrc={languageIcon} onClick={toggleLang} />
          </div>
        </section>


        {/* Account Summary & Purchase filters moved to left drawer menu */}



        {/* Tabs */}
        <Tabs id="portal-tabs" value={activeTab} onValueChange={setActiveTab}>
          <div className="hidden">
            <TabsList>
              <TabsTrigger value="purchases" />
              <TabsTrigger value="quotations" />
              <TabsTrigger value="wallet" />
              <TabsTrigger value="withdrawals" />
              <TabsTrigger value="referrals" />
              <TabsTrigger value="profile" />
            </TabsList>
          </div>

          {/* Purchases */}
          <TabsContent value="purchases" className="mt-4">
            {(() => {
              const groups: Record<string, string[]> = {
                completed: ["completed", "delivered", "partial_delivered"],
                pending:   ["pending", "confirmed", "processing", "ready_for_delivery"],
                returned:  ["returned"],
              };
              const filtered = salesFilter === "all" ? sales : sales.filter((s: any) => (groups[salesFilter] || []).includes(s.sale_status));
              const filterLabels: Record<string, string> = { all: T("all"), completed: T("completed"), pending: T("pending"), returned: T("returned") };
              return (
                <Card>
                  {salesFilter !== "all" && (
                    <div className="flex items-center justify-between gap-2 px-4 py-2 bg-slate-50 border-b border-slate-100 text-xs">
                      <span className="text-slate-600">{T("filter")}: <span className="font-semibold text-slate-800">{filterLabels[salesFilter]}</span> · {filtered.length} {T("count")}</span>
                      <button onClick={() => setSalesFilter("all")} className="text-violet-700 hover:text-violet-200 font-medium">{T("clearFilter")}</button>
                    </div>
                  )}
                  {filtered.length === 0 ? (
                    <EmptyState icon={ShoppingBag} text={T("noPurchases")} />
                  ) : (
                    <div className="divide-y divide-slate-100">
                      {filtered.map((s: any) => (
                        <div key={s.id} className="p-4 flex items-center justify-between gap-2 hover:bg-slate-50 transition">
                          <div className="min-w-0">
                            <div className="font-semibold text-sm truncate">#{s.invoice_no}</div>
                            <div className="text-[11px] text-slate-500 truncate mt-0.5">
                              {new Date(s.sale_date).toLocaleDateString()} · {s.payment_method} · {s.sale_status}
                            </div>
                          </div>
                          <div className="text-right shrink-0">
                            <div className="font-bold text-sm tabular-nums">৳{Number(s.total_amount).toFixed(2)}</div>
                            {Number(s.due_amount) > 0 && (
                              <Badge className="text-[10px] mt-1 bg-rose-500/15 text-rose-700 border-rose-500/30 hover:bg-rose-500/15">
                                {T("dueBadge")} ৳{Number(s.due_amount).toFixed(2)}
                              </Badge>
                            )}
                          </div>
                        </div>
                      ))}
                    </div>
                  )}
                </Card>
              );
            })()}
          </TabsContent>

          {/* Quotations */}
          <TabsContent value="quotations" className="mt-4 space-y-3">
            <div className="flex items-center justify-between">
              <h3 className="font-bold text-sm flex items-center gap-2"><FileText className="h-4 w-4 text-violet-400" />{T("myQuotations")}</h3>
              <Button size="sm" onClick={() => setQuoteOpen(true)} className="bg-violet-500 hover:bg-violet-600 text-white rounded-full h-8">
                <Plus className="h-3.5 w-3.5 mr-1" />{T("newQuotation")}
              </Button>
            </div>
            <Card>
              {myQuotes.length === 0 ? (
                <EmptyState icon={FileText} text={T("noQuotations")} />
              ) : (
                <div className="divide-y divide-slate-100">
                  {myQuotes.map((q: any) => (
                    <div key={q.id} className="p-3 flex items-center justify-between gap-3 flex-wrap hover:bg-slate-50 transition">
                      <div className="min-w-0">
                        <div className="flex items-center gap-2 flex-wrap">
                          <span className="font-mono text-xs text-slate-700">{q.quote_no}</span>
                          {quotationStatusBadge(q.status)}
                          {!q.for_self && (
                            <Badge variant="outline" className="text-[10px] border-slate-200 text-slate-700">
                              {T("refLabel")}: {q.referral_mobile}
                            </Badge>
                          )}
                        </div>
                        <div className="text-[11px] text-slate-500 mt-0.5">
                          {new Date(q.created_at).toLocaleString()} · {q.for_self ? T("forSelf") : (q.referral_name || T("refLabel"))}
                        </div>
                      </div>
                      <div className="flex items-center gap-2">
                        <div className="font-bold text-sm tabular-nums">৳{Number(q.total_amount).toLocaleString()}</div>
                        {q.status === "draft" && (
                          <>
                            <Button size="sm" variant="outline" className="h-8 border-slate-200 bg-slate-50 hover:bg-slate-100" onClick={async () => {
                              try { await submitQuoteFn({ data: { token: token!, id: q.id } }); toast.success(T("submitted")); refetchQuotes(); }
                              catch (e: any) { if (isAuthErr(e?.message)) { logout(); return; } toast.error(e?.message); }
                            }}>
                              <Send className="h-3.5 w-3.5" />
                            </Button>
                            <Button size="icon" variant="ghost" className="h-8 w-8 hover:bg-rose-500/15" onClick={async () => {
                              try { await delQuoteFn({ data: { token: token!, id: q.id } }); toast.success(T("deleted")); refetchQuotes(); }
                              catch (e: any) { if (isAuthErr(e?.message)) { logout(); return; } toast.error(e?.message); }
                            }}>
                              <Trash2 className="h-3.5 w-3.5 text-rose-400" />
                            </Button>
                          </>
                        )}
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </Card>
          </TabsContent>

          {/* Wallet History */}
          <TabsContent value="wallet" className="mt-4">
            <Card>
              {walletTx.length === 0 ? (
                <EmptyState icon={WalletCards} text={T("noTx")} />
              ) : (
                <div className="divide-y divide-slate-100">
                  {walletTx.map((tx: any) => {
                    const isCredit = Number(tx.amount) > 0 || tx.type === "commission_credit" || tx.type === "transfer_in";
                    return (
                      <div key={tx.id} className="p-4 flex items-center justify-between gap-2 hover:bg-slate-50 transition">
                        <div className="flex items-center gap-3 min-w-0">
                          <div className={`h-9 w-9 rounded-full grid place-items-center shrink-0 ${isCredit ? "bg-emerald-500/15 text-emerald-700" : "bg-rose-500/15 text-rose-700"}`}>
                            {isCredit ? <HandCoins className="h-4 w-4" /> : <Banknote className="h-4 w-4" />}
                          </div>
                          <div className="min-w-0">
                            <div className="font-medium text-sm capitalize truncate">{tx.type.replace(/_/g, " ")}</div>
                            <div className="text-[11px] text-slate-500">{new Date(tx.transaction_date).toLocaleString()}</div>
                            {tx.note && <div className="text-[11px] text-slate-600 mt-0.5 truncate">{tx.note}</div>}
                          </div>
                        </div>
                        <div className={`font-bold shrink-0 tabular-nums text-sm ${isCredit ? "text-emerald-700" : "text-rose-700"}`}>
                          {isCredit ? "+" : "−"}৳{Math.abs(Number(tx.amount)).toFixed(2)}
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
            </Card>
          </TabsContent>

          {/* Withdrawals */}
          <TabsContent value="withdrawals" className="mt-4">
            <Card>
              {withdrawals.length === 0 ? (
                <EmptyState icon={Banknote} text={T("noCashout")} />
              ) : (
                <div className="divide-y divide-slate-100">
                  {withdrawals.map((w: any) => (
                    <div key={w.id} className="p-4 flex items-center justify-between gap-2 hover:bg-slate-50 transition">
                      <div className="min-w-0">
                        <div className="font-semibold text-sm capitalize truncate">{w.method} · <span className="font-mono text-slate-600">{w.account_number}</span></div>
                        <div className="text-[11px] text-slate-500">{new Date(w.created_at).toLocaleString()}</div>
                      </div>
                      <div className="text-right shrink-0">
                        <div className="font-bold tabular-nums">৳{Number(w.amount).toFixed(2)}</div>
                        <Badge className={`text-[10px] mt-1 border ${
                          w.status === "approved" || w.status === "paid" ? "bg-emerald-500/15 text-emerald-700 border-emerald-500/30" :
                          w.status === "rejected" ? "bg-rose-500/15 text-rose-700 border-rose-500/30" :
                          "bg-amber-500/15 text-amber-700 border-amber-500/30"
                        }`}>
                          {w.status}
                        </Badge>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </Card>
          </TabsContent>

          {/* Referrals */}
          <TabsContent value="referrals" className="mt-4 space-y-4">
            <div className="flex items-center justify-between flex-wrap gap-2">
              <h3 className="font-bold flex items-center gap-2 text-sm"><UserPlus className="h-4 w-4 text-violet-400" /> {T("myReferrals")}</h3>
              <Button size="sm" onClick={() => setAddRefOpen(true)} className="bg-violet-500 hover:bg-violet-600 text-white rounded-full h-8">
                <Plus className="h-3.5 w-3.5 mr-1" />{T("addNumber")}
              </Button>
            </div>

            <Card>
              <div className="px-4 py-2.5 bg-slate-50 text-[11px] font-semibold uppercase tracking-wider text-slate-600 border-b border-slate-100">
                {T("waiting")} ({pendingReferrals.length})
              </div>
              {pendingReferrals.length === 0 ? (
                <EmptyState icon={Hourglass} text={T("noWaiting")} />
              ) : (
                <div className="divide-y divide-slate-100">
                  {pendingReferrals.map((p: any) => (
                    <div key={p.id} className="p-3 flex items-center justify-between gap-2">
                      <div className="min-w-0">
                        <div className="font-mono text-sm">{p.mobile}</div>
                        {p.note && <div className="text-[11px] text-slate-500 truncate">{p.note}</div>}
                        <div className="text-[10px] text-slate-600">{T("added")}: {new Date(p.created_at).toLocaleDateString()}</div>
                      </div>
                      <div className="flex items-center gap-2 shrink-0">
                        <Badge className="text-[10px] bg-amber-500/15 text-amber-700 border-amber-500/30 hover:bg-amber-500/15">{T("waiting")}</Badge>
                        <Button size="icon" variant="ghost" className="h-8 w-8 hover:bg-rose-500/15" onClick={() => delRefMut.mutate(p.id)} disabled={delRefMut.isPending}>
                          <Trash2 className="h-4 w-4 text-rose-400" />
                        </Button>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </Card>

            <Card>
              <div className="px-4 py-2.5 bg-slate-50 text-[11px] font-semibold uppercase tracking-wider text-slate-600 border-b border-slate-100">
                {T("joined")} ({referrals.length})
              </div>
              {referrals.length === 0 ? (
                <EmptyState icon={UserPlus} text={T("noOneJoined")} />
              ) : (
                <div className="overflow-x-auto">
                  <table className="w-full text-sm">
                    <thead className="text-[10px] uppercase text-slate-500 bg-slate-50">
                      <tr>
                        <th className="text-left p-3">#</th>
                        <th className="text-left p-3">{T("name")}</th>
                        <th className="text-left p-3">{T("mobile")}</th>
                        <th className="text-left p-3">{T("date")}</th>
                      </tr>
                    </thead>
                    <tbody className="divide-y divide-slate-100">
                      {referrals.map((r: any, i: number) => (
                        <tr key={r.id} className="hover:bg-slate-50 transition">
                          <td className="p-3 text-slate-500">{i + 1}</td>
                          <td className="p-3 font-medium">{(lang === "en" ? r.name || r.name_bn : r.name_bn || r.name) || "—"}</td>
                          <td className="p-3 font-mono text-slate-700">{r.mobile}</td>
                          <td className="p-3 text-xs text-slate-500">{new Date(r.created_at).toLocaleDateString()}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </Card>
          </TabsContent>

          {/* Profile */}
          <TabsContent value="profile" className="mt-4">
            <ProfilePanel customer={customer} token={token!} onChanged={refetch} T={T} fmtDate={fmtDate} />
          </TabsContent>
        </Tabs>
      </main>

      {/* Withdraw Dialog */}
      <WithdrawDialog
        open={withdrawOpen}
        onClose={() => setWithdrawOpen(false)}
        balance={balance}
        T={T}
        onSubmit={async (payload) => {
          const res = await reqWithdraw({ data: { token: token!, ...payload } });
          refetch();
          return res as { ok: boolean; id: string };
        }}
        onCheck={async (id) => {
          const r = await checkWithdraw({ data: { token: token!, id } });
          if (r.status !== "pending") refetch();
          return r;
        }}
      />

      {/* Add Referral Dialog */}
      <Dialog open={addRefOpen} onOpenChange={setAddRefOpen}>
        <DialogContent className="max-w-md w-[calc(100vw-2rem)] sm:w-full bg-white border-slate-200 text-slate-900">
          <DialogHeader>
            <DialogTitle className="text-slate-900">{T("addRefTitle")}</DialogTitle>
          </DialogHeader>
          <div className="space-y-3">
            <div>
              <Label className="text-xs text-slate-600">{T("mobileRequired")}</Label>
              <Input value={newRefMobile} onChange={(e) => setNewRefMobile(e.target.value)} placeholder={T("mobilePh")} inputMode="tel"
                className="bg-white border-slate-200 text-slate-900 mt-1" />
              <p className="text-[11px] text-slate-500 mt-1.5">{T("refHint")}</p>
            </div>
            <div>
              <Label className="text-xs text-slate-600">{T("noteOpt")}</Label>
              <Input value={newRefNote} onChange={(e) => setNewRefNote(e.target.value)} placeholder={T("notePh")}
                className="bg-white border-slate-200 text-slate-900 mt-1" />
            </div>
          </div>
          <DialogFooter className="flex-col sm:flex-row gap-2">
            <Button variant="outline" onClick={() => setAddRefOpen(false)} className="border-slate-200 bg-transparent hover:bg-slate-50 text-slate-800">{T("cancel")}</Button>
            <Button
              className="bg-violet-500 hover:bg-violet-600 text-white"
              onClick={() => {
                const m = newRefMobile.trim();
                if (m.length < 6) { toast.error(T("validMobile")); return; }
                addRefMut.mutate({ mobile: m, note: newRefNote.trim() });
              }}
              disabled={addRefMut.isPending}
            >{addRefMut.isPending ? "..." : T("add")}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Send Money Dialog */}
      <SendMoneyDialog
        open={sendOpen}
        onClose={() => setSendOpen(false)}
        balance={balance}
        T={T}
        lookup={async (mobile) => lookupRecipientFn({ data: { token: token!, mobile } })}
        send={async (payload) => {
          const res = await sendMoneyFn({ data: { token: token!, ...payload } });
          await refetch();
          return res as { ok: boolean; reference: string; amount: number; new_balance: number; recipient: { name: string; mobile: string } };
        }}
      />

      {/* Quotation Dialog */}
      <QuotationDialog
        open={quoteOpen}
        onClose={() => setQuoteOpen(false)}
        token={token!}
        customerType={(data as any)?.customer?.customer_type}
        onSaved={async () => {
          await queryClient.invalidateQueries({ queryKey: ["portal-quotations"] });
          await refetchQuotes();
        }}
      />

      {/* bKash-style bottom navigation */}
      <div className="h-20" aria-hidden />
      <nav className="fixed bottom-0 inset-x-0 z-50 bg-white border-t border-slate-200 shadow-[0_-4px_20px_-4px_rgba(0,0,0,0.08)]" style={{ paddingBottom: "env(safe-area-inset-bottom)" }}>
        <div className="mx-auto max-w-3xl grid grid-cols-4">
          {[
            { key: "home",      label: lang === "bn" ? "হোম"       : "Home",    icon: Home,     onClick: () => window.scrollTo({ top: 0, behavior: "smooth" }), active: activeTab === "" },
            { key: "purchases", label: lang === "bn" ? "কেনাকাটা"  : "Orders",  icon: ShoppingBag, onClick: () => scrollToTab("purchases"), active: activeTab === "purchases" },
            { key: "wallet",    label: lang === "bn" ? "ওয়ালেট"   : "Wallet",  icon: Wallet,   onClick: () => scrollToTab("wallet"), active: activeTab === "wallet" },
            { key: "menu",      label: lang === "bn" ? "মেনু"       : "Menu",    icon: Menu,     onClick: () => setMenuOpen(true), active: menuOpen },
          ].map((it) => {
            const Icon = it.icon;
            return (
              <button
                key={it.key}
                type="button"
                onClick={it.onClick}
                className="flex flex-col items-center justify-center gap-1 py-2.5 active:scale-95 transition-transform touch-manipulation"
              >
                <Icon className={`h-6 w-6 ${it.active ? "text-violet-600" : "text-black"}`} strokeWidth={it.active ? 2.5 : 2} />
                <span className={`text-[11px] font-medium ${it.active ? "text-violet-600" : "text-black"}`}>{it.label}</span>

              </button>
            );
          })}
        </div>
      </nav>
    </div>
  );
}

// ============ Withdraw Dialog ============
const MIN_WITHDRAW = 50;
const QUICK_AMOUNTS = [500, 1000, 2000];
const METHOD_LABEL: Record<string, string> = { bkash: "bKash", nagad: "Nagad", rocket: "Rocket", bank: "Bank" };

// Approx published cashout charges. Percent applied to gross; flat added on top.
// Sources: bKash 1.85% (Agent), Nagad 1.5%, Rocket 1.8%, Bank flat ৳10 handling.
const FEE_TABLE: Record<string, { percent: number; flat: number; label: string }> = {
  bkash:  { percent: 1.85, flat: 0,  label: "1.85%" },
  nagad:  { percent: 1.50, flat: 0,  label: "1.50%" },
  rocket: { percent: 1.80, flat: 0,  label: "1.80%" },
  bank:   { percent: 0,    flat: 10, label: "৳10" },
};

function calcFee(method: string, gross: number) {
  const f = FEE_TABLE[method] || { percent: 0, flat: 0, label: "—" };
  const raw = (gross * f.percent) / 100 + f.flat;
  const fee = Math.round(raw * 100) / 100;
  const net = Math.max(0, Math.round((gross - fee) * 100) / 100);
  return { fee, net, rateLabel: f.label };
}

// Normalize MFS mobile input: strip non-digits, drop +88/88 country prefix,
// auto-prepend 0 if the user starts with the operator digit (e.g. "17..." → "017..."),
// cap to 11 digits, and pretty-print as "01XXX XXXXXX".
function formatMfsMobile(raw: string): string {
  let d = (raw || "").replace(/\D/g, "");
  if (d.startsWith("88")) d = d.slice(2);
  if (d.length > 0 && d[0] !== "0") d = "0" + d;
  d = d.slice(0, 11);
  if (d.length <= 5) return d;
  return d.slice(0, 5) + " " + d.slice(5);
}

// Bank account: allow digits, optional dashes/spaces; sanitize for storage.
function formatBankAccount(raw: string): string {
  return (raw || "").replace(/[^0-9A-Za-z\-]/g, "").slice(0, 24);
}

function validateAccount(method: string, raw: string, T: TFn): string | null {
  const v = raw.trim();
  if (!v) return T("needAcc");
  if (method === "bank") {
    const clean = v.replace(/[\s-]/g, "");
    if (!/^[0-9A-Za-z]+$/.test(clean)) return T("bankAccBadChars");
    if (clean.length < 6) return T("bankAccShort");
    if (clean.length > 20) return T("bankAccLong");
    return null;
  }
  // bkash / nagad / rocket — BD mobile, 11 digits, starts with 01[3-9]
  const digits = v.replace(/\D/g, "");
  if (!/^01[3-9]\d{8}$/.test(digits)) return T("mfsBadMobile");
  return null;
}

// Mask all but the last `keep` chars; preserve a "01" prefix for mobiles.
function maskAccount(raw: string, method: string, keep = 4): string {
  const v = (raw || "").trim();
  if (!v) return "—";
  if (method === "bank") {
    const clean = v.replace(/[\s-]/g, "");
    if (clean.length <= keep) return clean;
    return "•".repeat(Math.max(4, clean.length - keep)) + clean.slice(-keep);
  }
  const digits = v.replace(/\D/g, "");
  if (digits.length < 7) return digits;
  const head = digits.slice(0, 2);
  const tail = digits.slice(-keep);
  const mid = "•".repeat(Math.max(0, digits.length - 2 - keep));
  return `${head}${mid} ${tail}`;
}

function validateAmount(raw: string, balance: number, T: TFn): { value: number; error: string | null } {
  const v = Number(raw);
  if (!raw || Number.isNaN(v) || v <= 0) return { value: 0, error: T("reqAmount") };
  if (!Number.isInteger(v)) return { value: v, error: T("wholeOnly") };
  if (v < MIN_WITHDRAW) return { value: v, error: T("minAmount") };
  if (v > balance) return { value: v, error: T("insufficient") };
  return { value: v, error: null };
}

type Step = "form" | "review" | "pending" | "approved" | "rejected" | "error";

type CheckResult = { id: string; status: string; note: string | null; processed_at: string | null; amount: number; method: string; account_number: string };

function WithdrawDialog({
  open, onClose, balance, T, onSubmit, onCheck,
}: {
  open: boolean;
  onClose: () => void;
  balance: number;
  T: TFn;
  onSubmit: (p: any) => Promise<{ ok: boolean; id: string }>;
  onCheck: (id: string) => Promise<CheckResult>;
}) {
  const initial = { amount: "", method: "bkash", account_number: "", note: "" };
  const [form, setForm] = useState(initial);
  const [step, setStep] = useState<Step>("form");
  const [touched, setTouched] = useState({ amount: false, account_number: false });
  const [errMsg, setErrMsg] = useState<string>("");
  const [requestId, setRequestId] = useState<string | null>(null);
  const [adminNote, setAdminNote] = useState<string>("");

  // Reset everything when the dialog opens
  useEffect(() => {
    if (open) {
      setForm(initial);
      setStep("form");
      setTouched({ amount: false, account_number: false });
      setErrMsg("");
      setRequestId(null);
      setAdminNote("");
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open]);

  // Poll request status while dialog is open and we're waiting on approval
  useEffect(() => {
    if (!open || step !== "pending" || !requestId) return;
    let cancelled = false;
    let attempts = 0;
    const tick = async () => {
      attempts += 1;
      try {
        const r = await onCheck(requestId);
        if (cancelled) return;
        if (r.status === "approved") {
          setAdminNote(r.note || "");
          setStep("approved");
          return;
        }
        if (r.status === "rejected") {
          setAdminNote(r.note || "");
          setStep("rejected");
          return;
        }
      } catch {
        // ignore transient errors; keep polling
      }
      if (cancelled) return;
      // back off: 4s for first ~30s, then 10s
      const delay = attempts < 8 ? 4000 : 10000;
      timer = window.setTimeout(tick, delay);
    };
    let timer = window.setTimeout(tick, 3000);
    return () => { cancelled = true; window.clearTimeout(timer); };
  }, [open, step, requestId, onCheck]);

  const noBalance = balance < MIN_WITHDRAW;
  const amountCheck = validateAmount(form.amount, balance, T);
  const accountError = validateAccount(form.method, form.account_number, T);
  const formValid = !noBalance && !amountCheck.error && !accountError;
  const remaining = Math.max(0, balance - (amountCheck.value || 0));
  const feeInfo = calcFee(form.method, amountCheck.value || 0);

  const mut = useMutation({
    mutationFn: async () => {
      const res = await onSubmit({
        amount: amountCheck.value,
        method: form.method,
        account_number: form.method === "bank" ? form.account_number.trim() : form.account_number.replace(/\D/g, ""),
        note: form.note.trim(),
      });
      return res;
    },
    onSuccess: (res) => {
      setRequestId(res?.id ?? null);
      setStep(res?.id ? "pending" : "approved");
    },
    onError: (e: any) => {
      setErrMsg(e?.message || T("failed"));
      setStep("error");
    },
  });

  const handleClose = () => {
    if (mut.isPending) return;
    onClose();
  };

  return (
    <Dialog open={open} onOpenChange={(o) => !o && handleClose()}>
      <DialogContent className="max-w-md w-[calc(100vw-2rem)] sm:w-full bg-white border-0 text-slate-900 p-0 overflow-hidden rounded-2xl shadow-2xl">
        {/* ============ FORM STEP ============ */}
        {step === "form" && (
          <>
            {/* bKash-style pink header */}
            <div className="bg-gradient-to-br from-[#7c3aed] to-[#b30f59] px-5 pt-5 pb-6 text-white">
              <DialogHeader>
                <DialogTitle className="text-white flex items-center gap-2 text-base font-semibold">
                  <Banknote className="h-5 w-5" />
                  {T("cashoutTitle")}
                </DialogTitle>
              </DialogHeader>
              <div className="mt-3">
                <div className="text-[11px] uppercase tracking-wider text-white/80">{T("availableBalance")}</div>
                <div className="mt-0.5 font-bold text-3xl text-white tabular-nums">৳{balance.toFixed(2)}</div>
                <div className="mt-1 text-[11px] text-white/70">{T("minAmount")} · {T("wholeOnly")}</div>
              </div>
            </div>

            <div className="px-5 py-4 space-y-3 max-h-[60vh] overflow-y-auto">
              {noBalance && (
                <div className="rounded-lg bg-amber-50 ring-1 ring-amber-300 p-2.5 flex items-start gap-2 text-amber-800 text-xs">
                  <AlertTriangle className="h-4 w-4 shrink-0 mt-0.5" />
                  <span>{T("noBalance")}</span>
                </div>
              )}

              {/* Amount */}
              <div>
                <Label className="text-xs text-slate-600 font-medium">{T("amount")}</Label>
                <div className="relative mt-1">
                  <span className="absolute left-3 top-1/2 -translate-y-1/2 text-[#7c3aed] text-base font-bold">৳</span>
                  <Input
                    type="number"
                    inputMode="numeric"
                    min={MIN_WITHDRAW}
                    max={balance}
                    step={1}
                    placeholder="0"
                    value={form.amount}
                    onChange={(e) => setForm({ ...form, amount: e.target.value })}
                    onBlur={() => setTouched((t) => ({ ...t, amount: true }))}
                    disabled={noBalance}
                    className="bg-slate-50 border-slate-200 text-slate-900 pl-8 tabular-nums h-11 text-base font-semibold focus-visible:ring-[#7c3aed]/30 focus-visible:border-[#7c3aed]"
                  />
                </div>
                {touched.amount && amountCheck.error && (
                  <p className="text-[11px] text-rose-600 mt-1">{amountCheck.error}</p>
                )}
                {!amountCheck.error && amountCheck.value > 0 && (
                  <div className="mt-2 rounded-lg bg-violet-50 ring-1 ring-violet-100 px-3 py-2 text-[11px] space-y-0.5 tabular-nums">
                    <div className="flex justify-between text-slate-600"><span>{T("fee")} ({feeInfo.rateLabel})</span><span className="text-rose-600 font-medium">−৳{feeInfo.fee.toFixed(2)}</span></div>
                    <div className="flex justify-between font-bold text-slate-900"><span>{T("netAmount")}</span><span className="text-[#7c3aed]">৳{feeInfo.net.toFixed(2)}</span></div>
                    <div className="flex justify-between text-slate-500"><span>{T("remaining")}</span><span>৳{remaining.toFixed(2)}</span></div>
                  </div>
                )}
              </div>

              {/* Quick amount chips */}
              {!noBalance && (
                <div>
                  <div className="text-[11px] text-slate-500 mb-1.5 font-medium">{T("quickAmount")}</div>
                  <div className="flex flex-wrap gap-1.5">
                    {QUICK_AMOUNTS.filter((a) => a <= balance).map((a) => (
                      <button
                        key={a}
                        type="button"
                        onClick={() => { setForm({ ...form, amount: String(a) }); setTouched((t) => ({ ...t, amount: true })); }}
                        className="px-3 py-1.5 rounded-full text-xs font-semibold bg-slate-100 hover:bg-violet-50 text-slate-700 ring-1 ring-slate-200 hover:ring-[#7c3aed]/40 hover:text-[#7c3aed] transition"
                      >৳{a.toLocaleString()}</button>
                    ))}
                    <button
                      type="button"
                      onClick={() => { setForm({ ...form, amount: String(Math.floor(balance)) }); setTouched((t) => ({ ...t, amount: true })); }}
                      className="px-3 py-1.5 rounded-full text-xs font-bold bg-[#7c3aed] hover:bg-[#b30f59] text-white transition"
                    >{T("max")}</button>
                  </div>
                </div>
              )}

              {/* Method */}
              <div>
                <Label className="text-xs text-slate-600 font-medium">{T("method")}</Label>
                <Select value={form.method} onValueChange={(v) => { setForm({ ...form, method: v, account_number: "" }); setTouched((t) => ({ ...t, account_number: false })); }}>
                  <SelectTrigger className="bg-slate-50 border-slate-200 text-slate-900 mt-1 h-11 focus:ring-[#7c3aed]/30"><SelectValue /></SelectTrigger>
                  <SelectContent className="bg-white border-slate-200 text-slate-900">
                    <SelectItem value="bkash">bKash</SelectItem>
                    <SelectItem value="nagad">Nagad</SelectItem>
                    <SelectItem value="rocket">Rocket</SelectItem>
                    <SelectItem value="bank">Bank</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              {/* Account number */}
              <div>
                <Label className="text-xs text-slate-600 font-medium">{T("accountNo")}</Label>
                <Input
                  value={form.account_number}
                  onChange={(e) => {
                    const v = form.method === "bank" ? formatBankAccount(e.target.value) : formatMfsMobile(e.target.value);
                    setForm({ ...form, account_number: v });
                  }}
                  onBlur={() => setTouched((t) => ({ ...t, account_number: true }))}
                  placeholder={form.method === "bank" ? "A/C No." : "01XXX XXXXXX"}
                  inputMode={form.method === "bank" ? "text" : "tel"}
                  autoComplete={form.method === "bank" ? "off" : "tel"}
                  maxLength={form.method === "bank" ? 32 : 13}
                  className="bg-slate-50 border-slate-200 text-slate-900 mt-1 tabular-nums h-11 focus-visible:ring-[#7c3aed]/30 focus-visible:border-[#7c3aed]"
                />
                {touched.account_number && accountError && (
                  <p className="text-[11px] text-rose-600 mt-1">{accountError}</p>
                )}
              </div>

              {/* Note */}
              <div>
                <Label className="text-xs text-slate-600 font-medium">{T("note")}</Label>
                <Textarea
                  rows={2}
                  maxLength={200}
                  value={form.note}
                  onChange={(e) => setForm({ ...form, note: e.target.value })}
                  className="bg-slate-50 border-slate-200 text-slate-900 mt-1 focus-visible:ring-[#7c3aed]/30 focus-visible:border-[#7c3aed]"
                />
              </div>
            </div>

            <DialogFooter className="flex-col sm:flex-row gap-2 px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button variant="ghost" onClick={handleClose} className="text-slate-600 hover:bg-slate-200 hover:text-slate-900">{T("cancel")}</Button>
              <Button
                onClick={() => { setTouched({ amount: true, account_number: true }); if (formValid) setStep("review"); }}
                disabled={!formValid}
                className="bg-[#7c3aed] hover:bg-[#b30f59] text-white disabled:opacity-50 rounded-full h-11 px-6 font-semibold shadow-md"
              >
                {T("next")} <ArrowRight className="h-4 w-4" />
              </Button>
            </DialogFooter>
          </>
        )}

        {/* ============ REVIEW STEP ============ */}
        {step === "review" && (
          <>
            <div className="bg-gradient-to-br from-[#7c3aed] to-[#b30f59] px-5 pt-5 pb-6 text-white">
              <DialogHeader>
                <DialogTitle className="text-white text-base font-semibold">{T("reviewTitle")}</DialogTitle>
              </DialogHeader>
              <div className="mt-3 text-center">
                <div className="text-[11px] uppercase tracking-wider text-white/80">{T("netAmount")}</div>
                <div className="mt-1 font-bold text-4xl text-white tabular-nums">৳{feeInfo.net.toFixed(2)}</div>
                <div className="mt-1 text-[11px] text-white/70 tabular-nums">
                  {T("grossAmount")}: ৳{amountCheck.value.toFixed(2)} · {T("fee")} ({feeInfo.rateLabel}): ৳{feeInfo.fee.toFixed(2)}
                </div>
              </div>
            </div>

            <div className="px-5 py-4 space-y-3">
              <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 divide-y divide-slate-200">
                <Row label={T("method")} value={METHOD_LABEL[form.method] || form.method} />
                <Row label={T("accountNo")} value={maskAccount(form.account_number, form.method)} mono />
                <Row label={T("grossAmount")} value={`৳${amountCheck.value.toFixed(2)}`} mono />
                <Row label={`${T("fee")} (${feeInfo.rateLabel})`} value={`−৳${feeInfo.fee.toFixed(2)}`} mono />
                <Row label={T("netAmount")} value={`৳${feeInfo.net.toFixed(2)}`} mono />
                {form.note.trim() && <Row label={T("note")} value={form.note.trim()} />}
                <Row label={T("remaining")} value={`৳${remaining.toFixed(2)}`} mono />
              </div>

              <p className="text-[10.5px] text-slate-500 leading-snug px-1">{T("feeNote")}</p>
            </div>

            <DialogFooter className="flex-col sm:flex-row gap-2 px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button variant="ghost" onClick={() => setStep("form")} disabled={mut.isPending} className="text-slate-600 hover:bg-slate-200 hover:text-slate-900">
                <ArrowLeft className="h-4 w-4" /> {T("back")}
              </Button>
              <Button onClick={() => mut.mutate()} disabled={mut.isPending} className="bg-[#7c3aed] hover:bg-[#b30f59] text-white rounded-full h-11 px-6 font-semibold shadow-md">
                {mut.isPending ? <><Loader2 className="h-4 w-4 animate-spin" /> ...</> : <>{T("confirm")} <CheckCircle2 className="h-4 w-4" /></>}
              </Button>
            </DialogFooter>
          </>
        )}

        {/* ============ PENDING STEP (awaiting admin) ============ */}
        {step === "pending" && (
          <>
            <DialogHeader><DialogTitle className="sr-only">{T("pendingTitle")}</DialogTitle></DialogHeader>
            <div className="px-5 py-8 text-center space-y-3 animate-in fade-in zoom-in-95 duration-300">
              <div className="mx-auto h-16 w-16 rounded-full bg-amber-100 ring-4 ring-amber-200 grid place-items-center">
                <Loader2 className="h-9 w-9 text-amber-600 animate-spin" />
              </div>
              <div>
                <div className="text-lg font-bold text-slate-900">{T("pendingTitle")}</div>
                <div className="text-xs text-slate-500 mt-1 px-4">{T("pendingDesc")}</div>
              </div>
              <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 p-3 inline-block text-left min-w-[220px]">
                <div className="text-[11px] text-slate-500">{T("netAmount")}</div>
                <div className="text-xl font-bold text-amber-600 tabular-nums">৳{feeInfo.net.toFixed(2)}</div>
                <div className="text-[11px] text-slate-500 mt-1.5 pt-1.5 border-t border-slate-200">{METHOD_LABEL[form.method]} · <span className="font-mono text-slate-700">{maskAccount(form.account_number, form.method)}</span></div>
              </div>
            </div>
            <DialogFooter className="px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button onClick={handleClose} variant="ghost" className="w-full text-slate-600 hover:bg-slate-200 hover:text-slate-900">{T("closeKeepOpen")}</Button>
            </DialogFooter>
          </>
        )}

        {/* ============ APPROVED STEP ============ */}
        {step === "approved" && (
          <>
            <DialogHeader><DialogTitle className="sr-only">{T("approvedTitle")}</DialogTitle></DialogHeader>
            <div className="px-5 py-8 text-center space-y-3 animate-in fade-in zoom-in-95 duration-300">
              <div className="mx-auto h-16 w-16 rounded-full bg-emerald-100 ring-4 ring-emerald-200 grid place-items-center">
                <CheckCircle2 className="h-9 w-9 text-emerald-600" />
              </div>
              <div>
                <div className="text-lg font-bold text-slate-900">{T("approvedTitle")}</div>
                <div className="text-xs text-slate-500 mt-1">{T("approvedDesc")}</div>
              </div>
              <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 p-3 inline-block text-left min-w-[220px]">
                <div className="text-[11px] text-slate-500">{T("netAmount")}</div>
                <div className="text-xl font-bold text-emerald-600 tabular-nums">৳{feeInfo.net.toFixed(2)}</div>
                <div className="mt-1.5 pt-1.5 border-t border-slate-200 space-y-0.5 text-[11px] tabular-nums">
                  <div className="flex justify-between text-slate-600"><span>{T("grossAmount")}</span><span>৳{amountCheck.value.toFixed(2)}</span></div>
                  <div className="flex justify-between text-slate-600"><span>{T("fee")} ({feeInfo.rateLabel})</span><span className="text-rose-600">−৳{feeInfo.fee.toFixed(2)}</span></div>
                </div>
                <div className="text-[11px] text-slate-500 mt-1.5 pt-1.5 border-t border-slate-200">{METHOD_LABEL[form.method]} · <span className="font-mono text-slate-700">{maskAccount(form.account_number, form.method)}</span></div>
                {adminNote && <div className="text-[11px] text-emerald-700 mt-1.5 pt-1.5 border-t border-slate-200 break-words">{adminNote}</div>}
              </div>
            </div>
            <DialogFooter className="px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button onClick={handleClose} className="w-full bg-[#7c3aed] hover:bg-[#b30f59] text-white rounded-full h-11 font-semibold shadow-md">{T("done")}</Button>
            </DialogFooter>
          </>
        )}

        {/* ============ REJECTED STEP ============ */}
        {step === "rejected" && (
          <>
            <DialogHeader><DialogTitle className="sr-only">{T("rejectedTitle")}</DialogTitle></DialogHeader>
            <div className="px-5 py-8 text-center space-y-3 animate-in fade-in zoom-in-95 duration-300">
              <div className="mx-auto h-16 w-16 rounded-full bg-rose-100 ring-4 ring-rose-200 grid place-items-center">
                <XCircle className="h-9 w-9 text-rose-600" />
              </div>
              <div>
                <div className="text-lg font-bold text-slate-900">{T("rejectedTitle")}</div>
                {adminNote && (
                  <div className="text-xs text-rose-700 mt-2 px-4">
                    <span className="text-slate-500">{T("rejectedDesc")}: </span>{adminNote}
                  </div>
                )}
              </div>
            </div>
            <DialogFooter className="px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button onClick={handleClose} className="w-full bg-[#7c3aed] hover:bg-[#b30f59] text-white rounded-full h-11 font-semibold shadow-md">{T("done")}</Button>
            </DialogFooter>
          </>
        )}

        {/* ============ ERROR STEP ============ */}
        {step === "error" && (
          <>
            <DialogHeader><DialogTitle className="sr-only">{T("failTitle")}</DialogTitle></DialogHeader>
            <div className="px-5 py-8 text-center space-y-3 animate-in fade-in zoom-in-95 duration-300">
              <div className="mx-auto h-16 w-16 rounded-full bg-rose-100 ring-4 ring-rose-200 grid place-items-center">
                <XCircle className="h-9 w-9 text-rose-600" />
              </div>
              <div>
                <div className="text-lg font-bold text-slate-900">{T("failTitle")}</div>
                <div className="text-xs text-rose-700 mt-1 break-words px-4">{errMsg}</div>
              </div>
            </div>
            <DialogFooter className="flex-col sm:flex-row gap-2 px-5 py-4 bg-slate-50 border-t border-slate-100">
              <Button variant="ghost" onClick={handleClose} className="text-slate-600 hover:bg-slate-200 hover:text-slate-900">{T("cancel")}</Button>
              <Button onClick={() => setStep("review")} className="bg-[#7c3aed] hover:bg-[#b30f59] text-white rounded-full h-11 px-6 font-semibold shadow-md">
                {T("retry")} <ArrowRight className="h-4 w-4" />
              </Button>
            </DialogFooter>
          </>
        )}
      </DialogContent>
    </Dialog>

  );
}

function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="flex items-center justify-between px-3 py-2.5 text-sm gap-3">
      <span className="text-slate-500 text-xs">{label}</span>
      <span className={`text-slate-900 font-semibold truncate ${mono ? "tabular-nums" : ""}`}>{value}</span>
    </div>
  );
}

// ============ Profile Panel ============
function ProfilePanel({ customer, token, onChanged, T, fmtDate }: { customer: any; token: string; onChanged: () => void; T: TFn; fmtDate: (d: string | null) => string }) {
  const updateProfile = useServerFn(customerPortalUpdateProfile);
  const changePassword = useServerFn(customerPortalChangePassword);
  const uploadImage = useServerFn(customerPortalUploadProfileImage);
  const removeImage = useServerFn(customerPortalRemoveProfileImage);

  const [form, setForm] = useState({
    name: customer?.name || "",
    name_bn: customer?.name_bn || "",
    email: customer?.email || "",
    address: customer?.address || "",
  });
  const [pw, setPw] = useState({ current_password: "", new_password: "", confirm: "" });
  const [imgBusy, setImgBusy] = useState(false);

  useEffect(() => {
    setForm({
      name: customer?.name || "",
      name_bn: customer?.name_bn || "",
      email: customer?.email || "",
      address: customer?.address || "",
    });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [customer?.id]);

  const saveMut = useMutation({
    mutationFn: async () => {
      if (!form.name.trim()) throw new Error(T("nameNeeded"));
      await updateProfile({ data: { token, ...form } });
    },
    onSuccess: () => { toast.success(T("profileUpdated")); onChanged(); },
    onError: (e: any) => toast.error(e?.message || T("saveFail")),
  });

  const pwMut = useMutation({
    mutationFn: async () => {
      if (pw.new_password.length < 4) throw new Error(T("pwShort"));
      if (pw.new_password !== pw.confirm) throw new Error(T("pwMismatch"));
      await changePassword({ data: { token, current_password: pw.current_password, new_password: pw.new_password } });
    },
    onSuccess: () => { toast.success(T("pwChanged")); setPw({ current_password: "", new_password: "", confirm: "" }); },
    onError: (e: any) => toast.error(e?.message || T("failed")),
  });

  const onPickImage = async (file: File) => {
    if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) { toast.warning(T("imgOnly")); return; }
    if (file.size > 5 * 1024 * 1024) { toast.warning(T("imgMax")); return; }
    setImgBusy(true);
    try {
      const data_url: string = await new Promise((res, rej) => {
        const r = new FileReader();
        r.onload = () => res(r.result as string);
        r.onerror = () => rej(new Error("Read failed"));
        r.readAsDataURL(file);
      });
      await uploadImage({ data: { token, data_url, content_type: file.type as any } });
      toast.success(T("imgUpdated"));
      onChanged();
    } catch (e: any) {
      toast.error(e?.message || T("uploadFail"));
    } finally { setImgBusy(false); }
  };

  return (
    <div className="space-y-4">
      {/* Profile image card */}
      <Card>
        <div className="p-5">
          <h3 className="font-bold text-sm mb-4 flex items-center gap-2"><Camera className="h-4 w-4 text-violet-400" />{T("profileImage")}</h3>
          <div className="flex items-center gap-4 flex-wrap">
            <Avatar className="h-20 w-20 ring-2 ring-slate-200">
              <AvatarImage src={customer?.image_url || undefined} />
              <AvatarFallback className="text-xl bg-gradient-to-br from-violet-500 to-violet-600 text-white">{(customer?.name_bn || customer?.name || "?").slice(0, 1)}</AvatarFallback>
            </Avatar>
            <div className="flex gap-2 flex-wrap">
              <label>
                <input type="file" accept="image/jpeg,image/png,image/webp" className="hidden" onChange={(e) => e.target.files?.[0] && onPickImage(e.target.files[0])} />
                <Button asChild size="sm" disabled={imgBusy} className="bg-violet-500 hover:bg-violet-600 text-white">
                  <span><Camera className="h-4 w-4 mr-1" />{imgBusy ? "..." : T("change")}</span>
                </Button>
              </label>
              {customer?.image_url && (
                <Button size="sm" variant="outline" className="border-slate-200 bg-transparent hover:bg-rose-500/15 hover:text-rose-700 text-slate-700"
                  onClick={async () => { await removeImage({ data: { token } }); toast.success(T("removed")); onChanged(); }}>
                  <Trash2 className="h-4 w-4 mr-1" />{T("remove")}
                </Button>
              )}
            </div>
          </div>
        </div>
      </Card>

      {/* Personal info */}
      <Card>
        <div className="p-5">
          <h3 className="font-bold text-sm mb-4 flex items-center gap-2"><UserIcon className="h-4 w-4 text-violet-400" />{T("personalInfo")}</h3>
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
            <Field label={T("nameEn")}><Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            <Field label={T("nameBn")}><Input value={form.name_bn} onChange={(e) => setForm({ ...form, name_bn: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            <Field label={T("mobileNo")} hint={T("mobileChangeHint")}>
              <Input value={customer?.mobile || ""} disabled className="bg-slate-100 border-slate-200 text-slate-600" />
            </Field>
            <Field label={T("email")}><Input type="email" value={form.email} onChange={(e) => setForm({ ...form, email: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            <div className="sm:col-span-2">
              <Field label={T("address")}><Textarea rows={2} value={form.address} onChange={(e) => setForm({ ...form, address: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            </div>
            <div className="sm:col-span-2 grid grid-cols-2 gap-3 text-xs">
              <div className="rounded-lg bg-slate-50 ring-1 ring-slate-200 p-2.5">
                <div className="text-slate-500 text-[10px] uppercase tracking-wider">{T("customerType")}</div>
                <div className="font-medium text-slate-800 mt-0.5 capitalize">{customer?.customer_type || "—"}</div>
              </div>
              <div className="rounded-lg bg-slate-50 ring-1 ring-slate-200 p-2.5">
                <div className="text-slate-500 text-[10px] uppercase tracking-wider">{T("lastLogin")}</div>
                <div className="font-medium text-slate-800 mt-0.5">{fmtDate(customer?.portal_last_login_at)}</div>
              </div>
            </div>
            <div className="sm:col-span-2">
              <ReferralInput customer={customer} token={token} onChanged={onChanged} T={T} />
            </div>
          </div>
          <div className="mt-4 flex justify-end">
            <Button onClick={() => saveMut.mutate()} disabled={saveMut.isPending} className="bg-violet-500 hover:bg-violet-600 text-white">
              {saveMut.isPending ? "..." : T("save")}
            </Button>
          </div>
        </div>
      </Card>

      {/* Password */}
      <Card>
        <div className="p-5">
          <h3 className="font-bold text-sm mb-4 flex items-center gap-2"><KeyRound className="h-4 w-4 text-violet-400" />{T("changePassword")}</h3>
          <div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
            <Field label={T("currentPw")}><Input type="password" value={pw.current_password} onChange={(e) => setPw({ ...pw, current_password: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            <Field label={T("newPw")}><Input type="password" value={pw.new_password} onChange={(e) => setPw({ ...pw, new_password: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
            <Field label={T("confirmPw")}><Input type="password" value={pw.confirm} onChange={(e) => setPw({ ...pw, confirm: e.target.value })} className="bg-white border-slate-200 text-slate-900" /></Field>
          </div>
          <div className="mt-4 flex justify-end">
            <Button onClick={() => pwMut.mutate()} disabled={pwMut.isPending || !pw.current_password || !pw.new_password} className="bg-violet-500 hover:bg-violet-600 text-white">
              {pwMut.isPending ? "..." : T("changeBtn")}
            </Button>
          </div>
        </div>
      </Card>
    </div>
  );
}

// ============ Referral Input ============
function ReferralInput({ customer, token, onChanged, T }: { customer: any; token: string; onChanged: () => void; T: TFn }) {
  const setReferral = useServerFn(customerPortalSetReferral);
  const [mobile, setMobile] = useState("");
  const mut = useMutation({
    mutationFn: async () => {
      const m = mobile.trim();
      if (!m) throw new Error(T("noMobile"));
      if (m === customer?.mobile) throw new Error(T("noSelfRef"));
      return setReferral({ data: { token, reference_mobile: m } });
    },
    onSuccess: (res: any) => {
      toast.success(`${T("refLinked")} ${res?.referrer?.name || ""}`);
      setMobile("");
      onChanged();
    },
    onError: (e: any) => toast.error(e?.message || T("failed")),
  });

  if (customer?.reference_mobile || customer?.reference_customer_id) {
    return (
      <div className="rounded-xl bg-emerald-500/10 ring-1 ring-emerald-500/30 p-3 text-xs text-emerald-200">
        <div className="flex items-center gap-2">
          <BadgeCheck className="h-4 w-4 shrink-0" />
          <div className="min-w-0">
            <div>{T("refIsSet")} <span className="font-semibold font-mono">{customer?.reference_mobile}</span></div>
            <div className="text-emerald-700/70 mt-0.5 text-[10px]">{T("refContactAdmin")}</div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="rounded-xl border border-dashed border-white/15 bg-slate-50 p-3 space-y-2">
      <Label className="text-xs text-slate-600">{T("refSetHint")}</Label>
      <div className="flex gap-2 flex-wrap sm:flex-nowrap">
        <Input inputMode="tel" placeholder="01XXXXXXXXX" value={mobile} onChange={(e) => setMobile(e.target.value)}
          className="flex-1 min-w-0 bg-white border-slate-200 text-slate-900" />
        <Button onClick={() => mut.mutate()} disabled={mut.isPending || !mobile.trim()} className="bg-violet-500 hover:bg-violet-600 text-white">
          {mut.isPending ? T("verifying") : T("set")}
        </Button>
      </div>
      <p className="text-[10px] text-slate-500">{T("refSetWarn")}</p>
    </div>
  );
}

// ============ UI primitives ============
function Section({ title, right, children }: { title: string; right?: React.ReactNode; children: React.ReactNode }) {
  return (
    <section className="rounded-2xl bg-white border border-slate-200 overflow-hidden shadow-lg shadow-slate-200/40">
      <div className="px-4 pt-3 pb-1 flex items-center justify-between">
        <h3 className="text-xs font-bold text-slate-700 uppercase tracking-wider">{title}</h3>
        {right}
      </div>
      {children}
    </section>
  );
}

function Card({ children }: { children: React.ReactNode }) {
  return <div className="rounded-2xl bg-white border border-slate-200 overflow-hidden shadow-lg shadow-slate-200/40">{children}</div>;
}

function Field({ label, hint, children }: { label: string; hint?: string; children: React.ReactNode }) {
  return (
    <div>
      <Label className="text-xs text-slate-600">{label}</Label>
      <div className="mt-1">{children}</div>
      {hint && <p className="text-[10px] text-slate-500 mt-1">{hint}</p>}
    </div>
  );
}

function EmptyState({ icon: Icon, text }: { icon: LucideIcon; text: string }) {
  return (
    <div className="py-12 flex flex-col items-center justify-center gap-2 text-slate-500">
      <div className="h-12 w-12 rounded-full bg-slate-100 ring-1 ring-slate-200 grid place-items-center text-slate-500">
        <Icon className="h-5 w-5" />
      </div>
      <span className="text-sm">{text}</span>
    </div>
  );
}

type Tone = "indigo" | "violet" | "emerald" | "amber" | "rose" | "fuchsia" | "cyan" | "slate";
const toneMap: Record<Tone, { bg: string; ring: string; fg: string; gradBg: string }> = {
  indigo:  { bg: "bg-violet-500/15",  ring: "ring-violet-500/30",  fg: "text-violet-700",  gradBg: "from-violet-500 to-violet-600" },
  violet:  { bg: "bg-violet-500/15",  ring: "ring-violet-500/30",  fg: "text-violet-700",  gradBg: "from-violet-500 to-violet-600" },
  emerald: { bg: "bg-emerald-500/15", ring: "ring-emerald-500/30", fg: "text-emerald-700", gradBg: "from-emerald-500 to-emerald-600" },
  amber:   { bg: "bg-amber-500/15",   ring: "ring-amber-500/30",   fg: "text-amber-700",   gradBg: "from-amber-500 to-amber-600" },
  rose:    { bg: "bg-rose-500/15",    ring: "ring-rose-500/30",    fg: "text-rose-700",    gradBg: "from-rose-500 to-rose-600" },
  fuchsia: { bg: "bg-fuchsia-500/15", ring: "ring-fuchsia-500/30", fg: "text-fuchsia-700", gradBg: "from-fuchsia-500 to-fuchsia-600" },
  cyan:    { bg: "bg-fuchsia-500/15", ring: "ring-fuchsia-500/30", fg: "text-fuchsia-700", gradBg: "from-fuchsia-500 to-fuchsia-600" },
  slate:   { bg: "bg-slate-500/15",   ring: "ring-slate-500/30",   fg: "text-slate-700",   gradBg: "from-slate-500 to-slate-600" },
};

function StatCard({ label, value, icon: Icon, tone = "slate", small }: { label: string; value: string; icon?: LucideIcon; tone?: Tone; small?: boolean }) {
  const t = toneMap[tone];
  return (
    <div className="rounded-xl bg-slate-50 ring-1 ring-slate-200 p-3 flex flex-col items-start gap-1.5 hover:bg-slate-100 transition">
      {Icon && (
        <div className={`h-8 w-8 rounded-lg grid place-items-center ${t.bg} ring-1 ${t.ring}`}>
          <Icon className={`h-4 w-4 ${t.fg}`} strokeWidth={2.25} />
        </div>
      )}
      <div className="text-[10px] text-slate-500 uppercase tracking-wider leading-tight truncate w-full">{label}</div>
      <div className={`font-bold leading-tight truncate w-full text-slate-900 tabular-nums ${small ? "text-xs" : "text-sm"}`}>{value}</div>
    </div>
  );
}

function MenuTile({ label, icon: Icon, onClick, tone = "indigo", imgSrc }: { label: string; icon: LucideIcon; onClick?: () => void; tone?: Tone; imgSrc?: string }) {
  const t = toneMap[tone];
  return (
    <button type="button" onClick={onClick}
      className="group flex flex-col items-center justify-start gap-1.5 rounded-xl p-2 hover:bg-slate-50 active:scale-95 transition-all">
      {imgSrc ? (
        <div className="h-12 w-12 shrink-0 rounded-2xl grid place-items-center p-1 group-hover:scale-110 group-hover:-translate-y-0.5 transition-all">
          <img src={imgSrc} alt={label} className="max-h-full max-w-full object-contain" />
        </div>
      ) : (
        <div className={`h-12 w-12 shrink-0 rounded-2xl grid place-items-center bg-gradient-to-br ${t.gradBg} shadow-lg shadow-black/30 group-hover:scale-110 group-hover:-translate-y-0.5 transition-all`}>
          <Icon className="h-5 w-5 text-white" strokeWidth={2.25} />
        </div>
      )}
      <div className="text-[11px] font-semibold text-slate-900 leading-tight text-center truncate w-full">{label}</div>
    </button>
  );
}


function CountUp({ value, duration = 600 }: { value: number; duration?: number }) {
  const [display, setDisplay] = useState(value);
  useEffect(() => {
    const start = display;
    const end = value;
    if (start === end) return;
    const startTime = performance.now();
    let raf = 0;
    const tick = (now: number) => {
      const p = Math.min(1, (now - startTime) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setDisplay(Math.round(start + (end - start) * eased));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value]);
  return <span className="tabular-nums">{display.toLocaleString("en-IN")}</span>;
}

function MiniStat({ label, value, icon: Icon, tone = "indigo", active, onClick }: { label: string; value: number; icon?: LucideIcon; tone?: Tone; active?: boolean; onClick?: () => void }) {
  const t = toneMap[tone];
  return (
    <button type="button" onClick={onClick}
      className={`group flex flex-col items-center gap-1.5 rounded-xl p-2.5 ring-1 transition-all ${active ? `${t.bg} ${t.ring} ring-2` : "bg-slate-50 ring-slate-200 hover:bg-slate-100"}`}>
      {Icon && (
        <div className={`h-8 w-8 rounded-lg grid place-items-center bg-gradient-to-br ${t.gradBg} shadow-md`}>
          <Icon className="h-4 w-4 text-white" strokeWidth={2.25} />
        </div>
      )}
      <div className={`text-lg font-extrabold leading-none ${active ? t.fg : "text-slate-900"}`}><CountUp value={value} /></div>
      <div className="text-[10px] text-slate-500 leading-tight">{label}</div>
    </button>
  );
}

type Recipient = { id: string; name: string; name_bn: string; mobile: string; image_url: string };
type SendResult = { ok: boolean; reference: string; amount: number; new_balance: number; recipient: { name: string; mobile: string } };

function SendMoneyDialog({
  open, onClose, balance, T, lookup, send,
}: {
  open: boolean;
  onClose: () => void;
  balance: number;
  T: TFn;
  lookup: (mobile: string) => Promise<Recipient>;
  send: (p: { recipient_mobile: string; amount: number; note: string }) => Promise<SendResult>;
}) {
  const [step, setStep] = useState<1 | 2 | 3 | 4>(1);
  const [mobile, setMobile] = useState("");
  const [recipient, setRecipient] = useState<Recipient | null>(null);
  const [amount, setAmount] = useState("");
  const [note, setNote] = useState("");
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<SendResult | null>(null);

  useEffect(() => {
    if (!open) {
      setTimeout(() => {
        setStep(1); setMobile(""); setRecipient(null);
        setAmount(""); setNote(""); setLoading(false); setResult(null);
      }, 200);
    }
  }, [open]);

  const num = Number(amount || 0);
  const valid = num > 0 && num <= balance;

  const doLookup = async () => {
    const m = mobile.trim();
    if (m.length < 6) { toast.error("সঠিক মোবাইল দিন"); return; }
    setLoading(true);
    try {
      const r = await lookup(m);
      setRecipient(r);
      setStep(2);
    } catch (e: any) {
      toast.error(e?.message || "Not found");
    } finally { setLoading(false); }
  };

  const doSend = async () => {
    if (!recipient) return;
    setLoading(true);
    try {
      const res = await send({ recipient_mobile: recipient.mobile, amount: num, note: note.trim() });
      setResult(res);
      setStep(4);
      toast.success(T("sendSuccess"));
    } catch (e: any) {
      toast.error(e?.message || T("sendFail"));
    } finally { setLoading(false); }
  };

  const fmt = (n: number) => `৳${Number(n || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

  return (
    <Dialog open={open} onOpenChange={(v) => { if (!v) onClose(); }}>
      <DialogContent className="max-w-md w-[calc(100vw-2rem)] sm:w-full bg-white border-slate-200 text-slate-900">
        <DialogHeader>
          <DialogTitle className="text-slate-900 flex items-center gap-2">
            <Send className="h-4 w-4 text-violet-400" />
            {T("sendMoneyTitle")}
          </DialogTitle>
        </DialogHeader>

        <div className="text-xs text-slate-600 -mt-1">
          {T("availableBalance")} <span className="font-bold text-emerald-700">{fmt(balance)}</span>
        </div>

        {step === 1 && (
          <div className="space-y-3">
            <div>
              <Label className="text-xs text-slate-600">{T("recipientMobile")}</Label>
              <Input
                value={mobile}
                onChange={(e) => setMobile(e.target.value)}
                placeholder="01XXXXXXXXX"
                inputMode="tel"
                className="bg-white border-slate-200 text-slate-900 mt-1"
              />
            </div>
            <DialogFooter className="flex-col sm:flex-row gap-2">
              <Button variant="outline" onClick={onClose} className="border-slate-200 bg-transparent hover:bg-slate-50 text-slate-800">{T("cancel")}</Button>
              <Button onClick={doLookup} disabled={loading} className="bg-violet-500 hover:bg-violet-600 text-white">
                {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Search className="h-4 w-4 mr-1" />}
                {T("searchRecipient")}
              </Button>
            </DialogFooter>
          </div>
        )}

        {step === 2 && recipient && (
          <div className="space-y-3">
            <div className="rounded-xl bg-white/60 border border-slate-100 p-3 flex items-center gap-3">
              <Avatar className="h-12 w-12 ring-2 ring-violet-500/40">
                {recipient.image_url ? <AvatarImage src={recipient.image_url} /> : null}
                <AvatarFallback className="bg-violet-500/20 text-violet-200 font-bold">
                  {(recipient.name || "?").slice(0, 2).toUpperCase()}
                </AvatarFallback>
              </Avatar>
              <div className="min-w-0">
                <div className="font-bold truncate">{recipient.name}</div>
                <div className="text-xs text-slate-600">{recipient.mobile}</div>
              </div>
              <BadgeCheck className="ml-auto h-5 w-5 text-emerald-400" />
            </div>

            <div>
              <Label className="text-xs text-slate-600">{T("sendAmount")}</Label>
              <Input
                type="number" min="1" max={balance} step="0.01"
                value={amount} onChange={(e) => setAmount(e.target.value)}
                placeholder="0.00"
                className="bg-white border-slate-200 text-slate-900 mt-1 text-xl font-bold tabular-nums"
              />
              {num > balance && <p className="text-[11px] text-rose-400 mt-1">{T("insufficient")}</p>}
            </div>
            <div>
              <Label className="text-xs text-slate-600">{T("sendNote")}</Label>
              <Textarea value={note} onChange={(e) => setNote(e.target.value)} rows={2}
                className="bg-white border-slate-200 text-slate-900 mt-1" />
            </div>

            <DialogFooter className="flex-col sm:flex-row gap-2">
              <Button variant="outline" onClick={() => setStep(1)} className="border-slate-200 bg-transparent hover:bg-slate-50 text-slate-800">
                <ArrowLeft className="h-4 w-4 mr-1" /> {T("back")}
              </Button>
              <Button disabled={!valid} onClick={() => setStep(3)} className="bg-violet-500 hover:bg-violet-600 text-white disabled:opacity-40">
                {T("reviewSend")} <ArrowRight className="h-4 w-4 ml-1" />
              </Button>
            </DialogFooter>
          </div>
        )}

        {step === 3 && recipient && (
          <div className="space-y-3">
            <div className="rounded-xl bg-gradient-to-br from-violet-500/20 to-violet-500/20 border border-violet-500/30 p-4 text-center">
              <div className="text-xs text-slate-600">{T("netAmount")}</div>
              <div className="text-3xl font-extrabold text-violet-100 mt-1 tabular-nums">{fmt(num)}</div>
              <div className="text-xs text-slate-600 mt-2">→ {recipient.name}</div>
              <div className="text-xs text-slate-500">{recipient.mobile}</div>
              {note && <div className="text-[11px] text-slate-600 mt-2 italic">"{note}"</div>}
            </div>
            <div className="rounded-lg bg-slate-100 p-3 text-xs space-y-1.5">
              <div className="flex justify-between"><span className="text-slate-600">{T("availableBalance")}</span><span className="font-semibold">{fmt(balance)}</span></div>
              <div className="flex justify-between"><span className="text-slate-600">{T("sendMoney")}</span><span className="font-semibold text-rose-700">- {fmt(num)}</span></div>
              <div className="flex justify-between border-t border-slate-100 pt-1.5"><span className="text-slate-600">{T("remaining")}</span><span className="font-bold text-emerald-700">{fmt(balance - num)}</span></div>
            </div>
            <DialogFooter className="flex-col sm:flex-row gap-2">
              <Button variant="outline" onClick={() => setStep(2)} disabled={loading} className="border-slate-200 bg-transparent hover:bg-slate-50 text-slate-800">
                <ArrowLeft className="h-4 w-4 mr-1" /> {T("back")}
              </Button>
              <Button onClick={doSend} disabled={loading} className="bg-emerald-500 hover:bg-emerald-600 text-white">
                {loading ? <Loader2 className="h-4 w-4 animate-spin mr-1" /> : <Send className="h-4 w-4 mr-1" />}
                {T("confirmSend")}
              </Button>
            </DialogFooter>
          </div>
        )}

        {step === 4 && result && (
          <div className="space-y-3 text-center py-2">
            <div className="mx-auto h-16 w-16 rounded-full bg-emerald-500/20 grid place-items-center">
              <CheckCircle2 className="h-10 w-10 text-emerald-400" />
            </div>
            <div className="text-lg font-bold">{T("sendSuccess")}</div>
            <div className="text-3xl font-extrabold text-emerald-700 tabular-nums">{fmt(result.amount)}</div>
            <div className="text-sm text-slate-600">→ {result.recipient.name} ({result.recipient.mobile})</div>
            <div className="rounded-lg bg-slate-100 p-3 text-xs space-y-1.5">
              <div className="flex justify-between"><span className="text-slate-600">{T("newBalance")}</span><span className="font-bold text-emerald-700">{fmt(result.new_balance)}</span></div>
              <div className="flex justify-between"><span className="text-slate-600">{T("txnRef")}</span><span className="font-mono text-[10px]">{result.reference}</span></div>
            </div>
            <DialogFooter>
              <Button onClick={onClose} className="w-full bg-violet-500 hover:bg-violet-600 text-white">{T("done")}</Button>
            </DialogFooter>
          </div>
        )}
      </DialogContent>
    </Dialog>
  );
}

export type { Lang };

