import React, { useEffect, useRef, useState } from "react";
import {
  Box,
  Typography,
  Paper,
  Button,
  CircularProgress,
  Snackbar,
  Alert,
  Autocomplete,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Chip,
} from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { Logout as LogoutIcon } from "@mui/icons-material";
import { ethers, Eip1193Provider, Contract } from "ethers";
import {
  TEXT,
  PRODUCTS,
  CHAINLINK_PRICE_FEED_ABI,
  ORACLEADDRESS,
  ERROR_MESSAGES,
  IUSD_TOKEN_ADDRESS,
  IUSD_ABI,
} from "../../const";
import IntelliwealthTextField from "../../components/intelliwealthTextField";
import TaskAltIcon from "@mui/icons-material/TaskAlt";
import ConfirmCloseDialog from "../../components/ConfirmCloseDialog";

type CustomEthereumProvider = Eip1193Provider & {
  isMetaMask?: boolean;
  on(
    event: "accountsChanged" | "chainChanged",
    listener: (...args: any[]) => void
  ): void;
  removeListener(
    event: "accountsChanged" | "chainChanged",
    listener: (...args: any[]) => void
  ): void;
};

const getEthereum = () =>
  (window as any).ethereum as CustomEthereumProvider | undefined;

// ---------------- Error helpers ----------------
const extractErrorMessage = (err: any): string => {
  try {
    if (!err) return "An unknown error occurred.";
    const msg =
      err?.reason ||
      err?.data?.message ||
      err?.data?.originalError?.message ||
      err?.error?.message ||
      err?.error?.data?.message ||
      err?.error?.data?.originalError?.message ||
      err?.info?.error?.message ||
      err?.info?.error?.data?.message ||
      err?.info?.error?.data?.originalError?.message ||
      err?.shortMessage ||
      err?.message ||
      String(err);
    return typeof msg === "string" ? msg : JSON.stringify(msg);
  } catch {
    return "An unknown error occurred.";
  }
};

const containsExecutionReverted = (err: any, fallbackMsg?: string): boolean => {
  const haystacks: string[] = [];
  try {
    if (fallbackMsg) haystacks.push(fallbackMsg);
    if (typeof err === "string") haystacks.push(err);
    if (err?.reason) haystacks.push(err.reason);
    if (err?.message) haystacks.push(err.message);
    if (err?.shortMessage) haystacks.push(err.shortMessage);
    if (err?.data?.message) haystacks.push(err.data.message);
    if (err?.data?.originalError?.message) haystacks.push(err.data.originalError.message);
    if (err?.error?.message) haystacks.push(err.error.message);
    if (err?.error?.data?.message) haystacks.push(err.error.data.message);
    if (err?.error?.data?.originalError?.message) haystacks.push(err.error.data.originalError.message);
    if (err?.info?.error?.message) haystacks.push(err.info.error.message);
    if (err?.info?.error?.data?.message) haystacks.push(err.info.error.data.message);
    if (err?.info?.error?.data?.originalError?.message) haystacks.push(err.info.error.data.originalError.message);
    const bodies = [err?.body, err?.error?.body, err?.info?.body].filter(Boolean);
    for (const body of bodies) {
      if (typeof body === "string") {
        try {
          const parsed = JSON.parse(body);
          const nested = [
            parsed?.error?.message,
            parsed?.error?.data?.message,
            parsed?.error?.data?.originalError?.message,
          ].filter(Boolean) as string[];
          haystacks.push(...nested);
        } catch (_) {
          haystacks.push(body);
        }
      }
    }
  } catch {}
  return haystacks.some((s) => typeof s === "string" && s.toLowerCase().includes("execution reverted"));
};

// ---------------- Types ----------------
interface Leg {
  maturity: number;
  entryPrice: number;
  amountToken: number;
  isLong: boolean;
}

interface Position {
  positionId: number;
  owner: string;
  purchaseTimestamp: number;
  isActive: boolean;
  closeTimestamp: number;
  positionType: number;
  stopLossPrice: number;
  takeProfitPrice: number;
  legs: Leg[];
  currentPnl: number;
}

type DashboardCacheEntry = {
  timestamp: number;
  spotPrice: number;
  tokenBalance: string;
  positions: Position[];
  unrealizedPnl: number;
  activePositionsCount: number;
};

const LS_AUTOCONNECT_KEY = "iw:autoConnect";     
const SS_FORCE_DC_KEY    = "iw:forceDisconnect";  
const CACHE_TTL_MS = 15_000;

const lsGet = (k: string) => { try { return localStorage.getItem(k); } catch { return null; } };
const lsSet = (k: string, v: string) => { try { localStorage.setItem(k, v); } catch {} };
const ssGet = (k: string) => { try { return sessionStorage.getItem(k); } catch { return null; } };
const ssSet = (k: string, v: string) => { try { sessionStorage.setItem(k, v); } catch {} };
const ssRemove = (k: string) => { try { sessionStorage.removeItem(k); } catch {} };

const shouldAutoConnect = () =>
  lsGet(LS_AUTOCONNECT_KEY) === "1" && ssGet(SS_FORCE_DC_KEY) !== "1";

const markAutoConnectOn = () => {
  lsSet(LS_AUTOCONNECT_KEY, "1");  
  ssRemove(SS_FORCE_DC_KEY);       
};

const markAutoConnectOff = () => {
  lsSet(LS_AUTOCONNECT_KEY, "0");   
  ssSet(SS_FORCE_DC_KEY, "1"); 
};

const Dashboard = () => {
  const theme = useTheme();
  const [account, setAccount] = useState<string | null>(null);
  const [balance, setBalance] = useState<string | null>(null);
  const [tokenBalance, setTokenBalance] = useState<string>("0");
  const [isLoading, setIsLoading] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string>("");
  const [snackbarOpen, setSnackbarOpen] = useState<boolean>(false);
  const [selectedInvestment, setSelectedInvestment] = useState<string>("Gold");
  const [unrealizedPnl, setUnrealizedPnl] = useState<number>(0);
  const [activePositionsCount, setActivePositionsCount] = useState<number>(0);
  const [spotPrice, setSpotPrice] = useState<number>(0);
  const [positions, setPositions] = useState<Position[]>([]);
  const [pendingClosePosition, setPendingClosePosition] = useState<Position | null>(null);
  const [isCloseProcessing, setIsCloseProcessing] = useState(false);
  const [isDataLoading, setIsDataLoading] = useState<boolean>(false);
  const investmentOptions = ["Gold", "Silver", "Oil", "Copper"];
  const dataCacheRef = useRef<Record<string, DashboardCacheEntry>>({});
  const requestIdRef = useRef(0);

  const shortenAddress = (address: string) =>
    `${address.slice(0, 6)}...${address.slice(-4)}`;
  const getPnlDisplay = () => formatPnlWithSign(unrealizedPnl);
  const getSpotName = () => selectedInvestment;
  const getTokenSymbol = () => {
    switch (selectedInvestment) {
      case "Gold": return "IGLD";
      case "Silver": return "ISILV";
      case "Oil": return "IWTI";
      case "Copper": return "ICU";
      default: return "";
    }
  };

  const formatPnlWithSign = (pnl: number): string => {
    if (isNaN(pnl)) return "+$0.00";
    const sign = pnl >= 0 ? "+" : "-";
    const formatted = Math.abs(pnl).toLocaleString("en-GB", {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    });
    return `${sign}$${formatted}`;
  };

  const getPnlColor = (value: number) =>
    value >= 0 ? "#10B981" : "#EF4444";

  const getPositionTypeLabel = (positionType: number) =>
    positionType === 0 ? "Outright" : "Spread";

  const isUserRejectedError = (err: any) => {
    const code = err?.code ?? err?.error?.code ?? err?.error?.error?.code;
    return code === 4001 || code === "ACTION_REJECTED";
    };

  const getUserRejectedMessage = (err: any) => {
    const detail =
      err?.error?.data?.message ||
      err?.data?.message ||
      err?.error?.message ||
      err?.message;

    if (typeof detail === "string") {
      const lower = detail.toLowerCase();
      if (lower.includes("user denied") || lower.includes("user rejected")) {
        return "Transaction cancelled in MetaMask (user denied signature).";
      }
      if (lower.includes("rejected")) {
        return "Transaction cancelled in MetaMask.";
      }
    }
    return "Transaction cancelled in MetaMask.";
  };

  const renderPositionTypeChip = (positionType: number) => {
    const isOutright = positionType === 0;
    return (
      <Chip
        label={isOutright ? "Outright" : "Spread"}
        size="small"
        sx={{
          borderRadius: "999px",
          fontWeight: 600,
          bgcolor: isOutright ? "rgba(96,165,250,.2)" : "rgba(196,181,253,.25)",
          color: isOutright ? "#1D4ED8" : "#7C3AED",
        }}
      />
    );
  };

  const handleSnackbarClose = () => {
    setSnackbarOpen(false);
    setErrorMessage("");
  };

  const connectToMetaMask = async () => {
    setIsLoading(true);
    try {
      const eth = getEthereum();
      if (!eth) {
        setErrorMessage(ERROR_MESSAGES.PLEASE_INSTALL_METAMASK_EXTENSION);
        setSnackbarOpen(true);
        return;
      }

      const provider = new ethers.BrowserProvider(eth as Eip1193Provider, "any");

      const existing = await provider.send("eth_accounts", []);
      const acct = existing?.[0];
      if (acct) {
        const network = await provider.getNetwork();
        if (Number(network.chainId) !== 42161) {
          setErrorMessage("Please switch to Arbitrum One.");
          setSnackbarOpen(true);
          setIsLoading(false);
          return;
        }
        const bal = await provider.getBalance(acct);
        setAccount(acct);
        setBalance(ethers.formatEther(bal));
        markAutoConnectOn(); // remember and allow eager connect
        await fetchContractData(acct, selectedInvestment);
        setIsLoading(false);
        return;
      }

      // Request access
      await new Promise((r) => setTimeout(r, 300));
      const accounts = await provider.send("eth_requestAccounts", []);
      if (!accounts || accounts.length === 0) {
        setErrorMessage("No accounts found. Please unlock MetaMask.");
        setSnackbarOpen(true);
        setIsLoading(false);
        return;
      }

      const network = await provider.getNetwork();
      if (Number(network.chainId) !== 42161) {
        setErrorMessage("Please switch to Arbitrum One.");
        setSnackbarOpen(true);
        setIsLoading(false);
        return;
      }

      const acct2 = accounts[0];
      const bal2 = await provider.getBalance(acct2);
      setAccount(acct2);
      setBalance(ethers.formatEther(bal2));
      markAutoConnectOn();
      await fetchContractData(acct2, selectedInvestment);
    } catch (error: any) {
      if (error?.code === -32002) {
        setErrorMessage("MetaMask is processing another request. Complete or cancel it, then try again.");
      } else {
        const msg = extractErrorMessage(error);
        const concise = containsExecutionReverted(error, msg)
          ? "Transaction error: execution reverted"
          : `Connection failed: ${msg.substring(0, 120)}`;
        setErrorMessage(concise);
      }
      setSnackbarOpen(true);
    } finally {
      setIsLoading(false);
    }
  };

  const disconnectWallet = () => {
    markAutoConnectOff();
    setAccount(null);
    setBalance(null);
    setTokenBalance("0");
    setUnrealizedPnl(0);
    setActivePositionsCount(0);
    setSpotPrice(0);
    setPositions([]);
    setErrorMessage("");
    setSnackbarOpen(false);
  };

  const applyCachedData = (cached: DashboardCacheEntry) => {
    setSpotPrice(cached.spotPrice);
    setTokenBalance(cached.tokenBalance);
    setPositions(cached.positions);
    setActivePositionsCount(cached.activePositionsCount);
    setUnrealizedPnl(cached.unrealizedPnl);
  };

  const fetchContractData = async (
    userAccount: string,
    investment: string,
    { showLoading }: { showLoading?: boolean } = {}
  ) => {
    const requestId = ++requestIdRef.current;
    if (showLoading !== false) setIsDataLoading(true);
    try {
      const eth = getEthereum();
      if (!eth) throw new Error(ERROR_MESSAGES.METAMASK_IS_NOT_INSTALLED);

      const provider = new ethers.BrowserProvider(eth as Eip1193Provider, "any");
      const network = await provider.getNetwork();
      if (Number(network.chainId) !== 42161) throw new Error("Please switch to Arbitrum One.");

      let tokenContract: Contract | undefined;
      let rfqContract: Contract;
      let amountField: string;
      let fallbackPrice: number;

      switch (investment) {
        case "Gold":
          tokenContract = new Contract(PRODUCTS.GOLD.TOKEN_ADDRESS, PRODUCTS.GOLD.TOKEN_ABI, provider);
          rfqContract = new Contract(PRODUCTS.GOLD.RFQ_CONTRACT_ADDRESS, PRODUCTS.GOLD.RFQ_ABI, provider);
          amountField = "amountIGLD";
          fallbackPrice = 0;
          break;
        case "Oil":
          rfqContract = new Contract(PRODUCTS.OIL.RFQ_CONTRACT_ADDRESS, PRODUCTS.OIL.RFQ_ABI, provider);
          amountField = "amountIWTI";
          fallbackPrice = 62.75;
          break;
        case "Silver":
          tokenContract = new Contract(PRODUCTS.SILVER.TOKEN_ADDRESS, PRODUCTS.SILVER.TOKEN_ABI, provider);
          rfqContract = new Contract(PRODUCTS.SILVER.RFQ_CONTRACT_ADDRESS, PRODUCTS.SILVER.RFQ_ABI, provider);
          amountField = "amountISILV";
          fallbackPrice = 0;
          break;
        case "Copper":
          tokenContract = new Contract(PRODUCTS.COPPER.TOKEN_ADDRESS, PRODUCTS.COPPER.TOKEN_ABI, provider);
          rfqContract = new Contract(PRODUCTS.COPPER.RFQ_CONTRACT_ADDRESS, PRODUCTS.COPPER.RFQ_ABI, provider);
          amountField = "amountICU";
          fallbackPrice = 0;
          break;
        default:
          throw new Error(`${ERROR_MESSAGES.UNSUPPORTED_INVESTMENT} ${investment}`);
      }

      const nowTs = Math.floor(Date.now() / 1000);
      const spotPromise = rfqContract
        .priceFor(nowTs)
        .then((priceWei) => parseFloat(ethers.formatUnits(priceWei, 18)) || fallbackPrice)
        .catch((e) => {
          if (investment === "Copper") {
            console.error("Error fetching copper price:", e);
          }
          return fallbackPrice;
        });

      const tokenBalancePromise = tokenContract
        ? tokenContract.balanceOf(userAccount).then((bal) => ethers.formatUnits(bal, 18))
        : Promise.resolve("0");

      const positionsPromise = (async () => {
        const nextPositionId = await rfqContract.nextPositionIdForUser(userAccount);
        const count = Number(nextPositionId);
        if (count === 0) {
          return { positions: [] as Position[], totalPnl: BigInt(0) };
        }

        const positionIds = Array.from({ length: count }, (_, i) => BigInt(i));
        const positionResults = await Promise.all(
          positionIds.map((id) => rfqContract.getPositionById(userAccount, id))
        );
        const rawPositions = positionResults.filter((pos: any) => pos.isActive);
        if (rawPositions.length === 0) {
          return { positions: [] as Position[], totalPnl: BigInt(0) };
        }

        const maturitySet = new Set<string>();
        rawPositions.forEach((p: any) =>
          p.legs.forEach((leg: any) => maturitySet.add(leg.maturity.toString()))
        );
        const maturityArr = Array.from(maturitySet);
        const priceResults = await Promise.all(
          maturityArr.map((m) => rfqContract.priceFor(BigInt(m)))
        );
        const priceMap: Record<string, bigint> = {};
        maturityArr.forEach((m, idx) => {
          priceMap[m] = priceResults[idx] as bigint;
        });

        let totalPnl = BigInt(0);
        const userPositions: Position[] = rawPositions
          .map((p: any) => {
            let posPnl = BigInt(0);
            let longAmount = BigInt(0);

            p.legs.forEach((leg: any) => {
              const currentPrice = priceMap[leg.maturity.toString()];
              const entry = BigInt(leg.entryPrice);
              const amt = BigInt(leg[amountField]);
              const one = ethers.parseUnits("1", 18);
              const legPnl = ((currentPrice - entry) * amt) / one;
              if (leg.isLong) { posPnl += legPnl; longAmount += amt; }
              else { posPnl -= legPnl; }
            });

            totalPnl += posPnl;

            return {
              positionId: Number(p.positionId),
              owner: p.owner,
              purchaseTimestamp: Number(p.purchaseTimestamp),
              isActive: p.isActive,
              closeTimestamp: Number(p.closeTimestamp),
              positionType: Number(p.positionType),
              stopLossPrice: parseFloat(ethers.formatUnits(p.stopLossPrice, 18)),
              takeProfitPrice: parseFloat(ethers.formatUnits(p.takeProfitPrice, 18)),
              legs: p.legs.map((leg: any) => ({
                maturity: Number(leg.maturity),
                entryPrice: parseFloat(ethers.formatUnits(leg.entryPrice, 18)),
                amountToken: parseFloat(ethers.formatUnits(leg[amountField], 18)),
                isLong: leg.isLong,
              })),
              currentPnl: parseFloat(ethers.formatUnits(posPnl, 18)),
            } as Position;
          })
          .reverse();

        return { positions: userPositions, totalPnl };
      })();

      const [nextSpotPrice, nextTokenBalance, positionsResult] = await Promise.all([
        spotPromise,
        tokenBalancePromise,
        positionsPromise,
      ]);

      if (requestId !== requestIdRef.current) return;

      setSpotPrice(nextSpotPrice);
      setTokenBalance(nextTokenBalance);
      setPositions(positionsResult.positions);
      setActivePositionsCount(positionsResult.positions.length);
      setUnrealizedPnl(parseFloat(ethers.formatUnits(positionsResult.totalPnl, 18)));

      const cacheKey = `${userAccount}:${investment}`;
      dataCacheRef.current[cacheKey] = {
        timestamp: Date.now(),
        spotPrice: nextSpotPrice,
        tokenBalance: nextTokenBalance,
        positions: positionsResult.positions,
        unrealizedPnl: parseFloat(ethers.formatUnits(positionsResult.totalPnl, 18)),
        activePositionsCount: positionsResult.positions.length,
      };
    } catch (error: any) {
      if (requestId !== requestIdRef.current) return;
      console.error(`Error fetching data for ${investment}:`, error);
      setSpotPrice(0);
      setUnrealizedPnl(0);
      setActivePositionsCount(0);
      setTokenBalance("0");
      setPositions([]);
      const msg = extractErrorMessage(error);
      const concise = msg.includes("Oracle price is stale")
        ? "Oracle is stale. Some data may be unavailable."
        : `Failed to load ${investment} data: ${msg.substring(0, 140)}`;
      setErrorMessage(concise);
      setSnackbarOpen(true);
    } finally {
      if (requestId === requestIdRef.current) setIsDataLoading(false);
    }
  };

  // ---------------- Close position ----------------
  const closePositionOnChain = async (positionId: number) => {
    try {
      const eth = getEthereum();
      if (!eth) { setErrorMessage(ERROR_MESSAGES.METAMASK_IS_NOT_INSTALLED); setSnackbarOpen(true); return; }

      const provider = new ethers.BrowserProvider(eth as Eip1193Provider, "any");
      const network = await provider.getNetwork();
      if (Number(network.chainId) !== 42161) { setErrorMessage("Please switch to Arbitrum One."); setSnackbarOpen(true); return; }

      const signer = await provider.getSigner();
      const userAddr = await signer.getAddress();

      let rfqAddress: string;
      let rfqAbi: any[];
      let tokenAddress: string | undefined;
      let tokenAbi: any[] | undefined;
      let amountKey: string;

      switch (selectedInvestment) {
        case "Gold":
          rfqAddress = PRODUCTS.GOLD.RFQ_CONTRACT_ADDRESS; rfqAbi = PRODUCTS.GOLD.RFQ_ABI;
          tokenAddress = PRODUCTS.GOLD.TOKEN_ADDRESS; tokenAbi = PRODUCTS.GOLD.TOKEN_ABI; amountKey = "amountIGLD"; break;
        case "Silver":
          rfqAddress = PRODUCTS.SILVER.RFQ_CONTRACT_ADDRESS; rfqAbi = PRODUCTS.SILVER.RFQ_ABI;
          tokenAddress = PRODUCTS.SILVER.TOKEN_ADDRESS; tokenAbi = PRODUCTS.SILVER.TOKEN_ABI; amountKey = "amountISILV"; break;
        case "Oil":
          rfqAddress = PRODUCTS.OIL.RFQ_CONTRACT_ADDRESS; rfqAbi = PRODUCTS.OIL.RFQ_ABI;
          tokenAddress = PRODUCTS.OIL.TOKEN_ADDRESS; tokenAbi = PRODUCTS.OIL.IWTI_ABI || PRODUCTS.OIL.TOKEN_ABI; amountKey = "amountIWTI"; break;
        case "Copper":
          rfqAddress = PRODUCTS.COPPER.RFQ_CONTRACT_ADDRESS; rfqAbi = PRODUCTS.COPPER.RFQ_ABI;
          tokenAddress = PRODUCTS.COPPER.TOKEN_ADDRESS; tokenAbi = PRODUCTS.COPPER.TOKEN_ABI; amountKey = "amountICU"; break;
        default:
          setErrorMessage(`${ERROR_MESSAGES.UNSUPPORTED_INVESTMENT} ${selectedInvestment}`); setSnackbarOpen(true); return;
      }

      const rfq = new Contract(rfqAddress, rfqAbi, signer);

      const pid = BigInt(positionId);
      const pos = await rfq.getPositionById(userAddr, pid);
      const legs: Array<{ maturity: bigint; entryPrice: bigint; [k: string]: any; isLong: boolean }> = pos.legs as any;

      const currentPrices: bigint[] = (await Promise.all(legs.map((leg) => rfq.priceFor(leg.maturity)))) as bigint[];

      let pnlValue = BigInt(0);
      let totalLongToBurn = BigInt(0);
      legs.forEach((leg, idx) => {
        const currentPrice = currentPrices[idx];
        const amount = BigInt(leg[amountKey] ?? 0);
        const pnlForLeg = ((currentPrice - leg.entryPrice) * amount) / ethers.parseUnits("1", 18);
        if (leg.isLong) { pnlValue += pnlForLeg; totalLongToBurn += amount; } else { pnlValue -= pnlForLeg; }
      });

      if (pnlValue < BigInt(0)) {
        const lossAmount = -pnlValue;
        const iusd = new Contract(IUSD_TOKEN_ADDRESS, IUSD_ABI as any, signer);
        const allowance = (await iusd.allowance(userAddr, rfqAddress)) as bigint;
        if (allowance < lossAmount) { const tx = await iusd.approve(rfqAddress, ethers.MaxUint256); await tx.wait(); }
      }

      if (totalLongToBurn > BigInt(0) && tokenAddress && tokenAbi) {
        const token = new Contract(tokenAddress, tokenAbi as any, signer);
        const allowance = (await token.allowance(userAddr, rfqAddress)) as bigint;
        if (allowance < totalLongToBurn) { const tx = await token.approve(rfqAddress, ethers.MaxUint256); await tx.wait(); }
      }

      const closeTx = await rfq.closePosition(pid, IUSD_TOKEN_ADDRESS);
      await closeTx.wait();

      await fetchContractData(userAddr, selectedInvestment);
    } catch (e: any) {
      console.error("Close position failed:", e);
      if (!isUserRejectedError(e)) {
        const msg = extractErrorMessage(e);
        const concise = containsExecutionReverted(e, msg)
          ? "Transaction error: execution reverted"
          : `Close failed: ${msg.substring(0, 140)}`;
        setErrorMessage(concise);
        setSnackbarOpen(true);
      }
      throw e;
    }
  };

  const handleRequestClosePosition = (position: Position) => setPendingClosePosition(position);
  const handleCancelClosePosition = () => { if (!isCloseProcessing) setPendingClosePosition(null); };
  const handleConfirmClosePosition = async () => {
    if (!pendingClosePosition) return;
    setIsCloseProcessing(true);
    try { await closePositionOnChain(pendingClosePosition.positionId); setPendingClosePosition(null); }
    catch (err: any) {
      if (isUserRejectedError(err)) {
        setPendingClosePosition(null);
        setErrorMessage(getUserRejectedMessage(err));
        setSnackbarOpen(true);
      }
    } finally { setIsCloseProcessing(false); }
  };

  // ---------------- Eager auto-connect on mount (guarded) ----------------
  useEffect(() => {
    const autoConnect = async () => {
      try {
        if (!shouldAutoConnect()) return;
        const eth = getEthereum(); if (!eth) return;
        const provider = new ethers.BrowserProvider(eth as Eip1193Provider, "any");
        const accounts = await provider.send("eth_accounts", []);
        const acct = accounts?.[0]; if (!acct) return;

        const network = await provider.getNetwork();
        if (Number(network.chainId) !== 42161) {
          setErrorMessage("Please switch to Arbitrum One.");
          setSnackbarOpen(true);
          return;
        }

        const bal = await provider.getBalance(acct);
        setAccount(acct);
        setBalance(ethers.formatEther(bal));
        await fetchContractData(acct, selectedInvestment);
      } catch (e) {
        console.error("Auto-connect failed:", e);
      }
    };
    autoConnect();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Re-fetch on account/instrument change
  useEffect(() => {
    if (!account || !selectedInvestment) return;
    const cacheKey = `${account}:${selectedInvestment}`;
    const cached = dataCacheRef.current[cacheKey];
    if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
      applyCachedData(cached);
      fetchContractData(account, selectedInvestment, { showLoading: false });
    } else {
      fetchContractData(account, selectedInvestment);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [account, selectedInvestment]);

  // Provider listeners
  useEffect(() => {
    const eth = getEthereum();
    if (!eth?.isMetaMask) {
      setErrorMessage(ERROR_MESSAGES.PLEASE_INSTALL_METAMASK_EXTENSION);
      setSnackbarOpen(true);
      return;
    }

    const handleAccountsChanged = async (accounts: string[]) => {
      if (accounts.length > 0) {
        // If currently disconnected AND user forced disconnect, ignore silent presence
        if (!account && ssGet(SS_FORCE_DC_KEY) === "1") return;

        const newAccount = accounts[0];
        setAccount(newAccount);
        try {
          const ethInner = getEthereum(); if (!ethInner) return;
          const provider = new ethers.BrowserProvider(ethInner as Eip1193Provider, "any");
          const network = await provider.getNetwork();
          if (Number(network.chainId) !== 42161) {
            setErrorMessage("Please switch to Arbitrum One.");
            setSnackbarOpen(true);
            return;
          }
          const balance = await provider.getBalance(newAccount);
          setBalance(ethers.formatEther(balance));
          await fetchContractData(newAccount, selectedInvestment);
        } catch (error: any) {
          console.error("Error handling account change:", error);
          const msg = extractErrorMessage(error);
          setErrorMessage(`Failed to update account: ${msg.substring(0, 140)}`);
          setSnackbarOpen(true);
        }
      } else {
        disconnectWallet();
      }
    };

    const handleChainChanged = (..._args: any[]) => { window.location.reload(); };

    eth.on("accountsChanged", handleAccountsChanged);
    eth.on("chainChanged", handleChainChanged);
    return () => {
      const ethCleanup = getEthereum();
      if (ethCleanup) {
        ethCleanup.removeListener("accountsChanged", handleAccountsChanged);
        ethCleanup.removeListener("chainChanged", handleChainChanged);
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedInvestment, account]);

  // ---------------- UI ----------------
  return (
    <Box sx={{ p: 4, bgcolor: "#F7FAFC", minHeight: "100vh" }}>
      <Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 4 }}>
        <Box>
          <Typography variant="h4" sx={{ color: "#1A202C", fontWeight: 600, letterSpacing: "-0.3px", mb: 2 }}>
            {TEXT.DASHBOARD}
          </Typography>
          <Typography variant="body2" sx={{ color: "#718096", fontSize: "0.95rem", lineHeight: 1.4, mb: 2 }}>
            {TEXT.WELCOME_BACK}
          </Typography>
          <Autocomplete
            options={["Gold", "Silver", "Oil", "Copper"]}
            value={selectedInvestment}
            onChange={(_, v) => setSelectedInvestment(v || "Gold")}
            renderInput={(params) => (
              <IntelliwealthTextField
                {...params}
                label="Select Investment"
                fullWidth={false}
                sx={{
                  width: 300,
                  "& .MuiOutlinedInput-root": { borderRadius: "8px" },
                  "& .MuiInputLabel-root": { fontSize: "16px" },
                  "& .MuiInputBase-input": { fontSize: "16px" },
                }}
              />
            )}
          />
        </Box>

        <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {account ? (
            <>
              <Button
                variant="outlined"
                startIcon={<LogoutIcon />}
                onClick={disconnectWallet}
                sx={{
                  borderColor: "#CBD5E0",
                  color: "#4A5568",
                  borderRadius: "8px",
                  p: "10px",
                  fontSize: "0.9rem",
                  textTransform: "none",
                  "&:hover": { borderColor: "#0D1629", bgcolor: "#EDF2F7" },
                }}
              >
                {TEXT.DISCONNECT_WALLET}
              </Button>
              <Chip
                label={shortenAddress(account)}
                icon={<TaskAltIcon sx={{ fontSize: "1rem", mr: 0.5 }} />}
                sx={{
                  mt: 1,
                  backgroundColor: "#EBF9F0",
                  color: "#2ECC71",
                  fontSize: "0.85rem",
                  maxWidth: "300px",
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                  "& .MuiChip-icon": { color: "#2ECC71" },
                }}
              />
            </>
          ) : (
            <Button
              variant="contained"
              onClick={connectToMetaMask}
              disabled={isLoading}
              sx={{
                backgroundColor: "#0D1629",
                color: "#fff",
                borderRadius: "8px",
                p: "10px",
                fontSize: "0.9rem",
                textTransform: "none",
                "&:hover": { backgroundColor: "#0D1629" },
                "&.Mui-disabled": { backgroundColor: "#CBD5E0", color: "#A0AEC0" },
              }}
            >
              {isLoading ? <CircularProgress size={20} color="inherit" /> : "Connect Wallet"}
            </Button>
          )}
        </Box>
      </Box>

      {isDataLoading ? (
        <Box sx={{ display: "flex", justifyContent: "center", my: 4 }}>
          <CircularProgress />
        </Box>
      ) : (
        <>
          <Box sx={{ display: "flex", gap: 3, mb: 4 }}>
            <Paper elevation={1} sx={{ p: 2, flexGrow: 1, display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center" }}>
              <Typography variant="h6" sx={{ fontWeight: "medium", color: "#6B7280" }}>{TEXT.UNREALIZED}</Typography>
              <Typography variant="h4" sx={{ fontWeight: "bold", mt: 1, color: getPnlColor(unrealizedPnl) }}>{getPnlDisplay()}</Typography>
            </Paper>
            <Paper elevation={1} sx={{ p: 2, flexGrow: 1, display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center" }}>
              <Typography variant="h6" sx={{ fontWeight: "medium", color: "#6B7280" }}>{TEXT.ACTIVE_POSITIONS}</Typography>
              <Typography variant="h4" sx={{ fontWeight: "bold", mt: 1, color: "#4B5563" }}>{activePositionsCount}</Typography>
            </Paper>
            <Paper elevation={1} sx={{ p: 2, flexGrow: 1, display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center" }}>
              <Typography variant="h6" sx={{ fontWeight: "medium", color: "#6B7280" }}>Spot {getSpotName()} Price</Typography>
              <Typography variant="h4" sx={{ fontWeight: "bold", mt: 1, color: "#4B5563" }}>${spotPrice.toLocaleString("en-GB", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</Typography>
            </Paper>
          </Box>

          <Box sx={{ mb: 4 }}>
            <Typography variant="h6" sx={{ fontWeight: "bold", mb: 2 }}>{TEXT.YOUR_POSITIONS}</Typography>
            <TableContainer component={Paper}>
              <Table sx={{ minWidth: 650 }}>
                <TableHead sx={{ bgcolor: "#F9FAFB" }}>
                  <TableRow>
                    <TableCell>ID</TableCell>
                    <TableCell>Type</TableCell>
                    <TableCell>Legs</TableCell>
                    <TableCell>Long Amount</TableCell>
                    <TableCell>Current P/L</TableCell>
                    <TableCell>SL / TP</TableCell>
                    <TableCell>Action</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {positions.length > 0 ? positions.map((position) => (
                    <TableRow key={position.positionId}>
                      <TableCell>{position.positionId}</TableCell>
                      <TableCell>{renderPositionTypeChip(position.positionType)}</TableCell>
                      <TableCell>
                        <Box sx={{ display: "flex", flexDirection: "column", gap: 0.5 }}>
                          {position.legs.map((leg, idx) => {
                            const date = new Date(leg.maturity * 1000);
                            const dd = String(date.getDate()).padStart(2, "0");
                            const mm = String(date.getMonth() + 1).padStart(2, "0");
                            const yyyy = date.getFullYear();
                            const dir = leg.isLong ? "Long" : "Short";
                            const amt = isNaN(leg.amountToken) ? 0 : leg.amountToken;
                            const entry = isNaN(leg.entryPrice) ? 0 : leg.entryPrice;
                            const dirColor = leg.isLong ? "#10B981" : "#EF4444";
                            return (
                              <Typography key={idx} variant="body2" sx={{ whiteSpace: "nowrap", color: "#374151" }}>
                                <Typography component="span" variant="body2" sx={{ color: dirColor, fontWeight: 700, mr: 0.5 }}>{dir}</Typography>
                                <Typography component="span" variant="body2" sx={{ fontWeight: 500, color: "#374151" }}>
                                  {`${amt.toFixed(2)} @ ${dd}/${mm}/${yyyy}`}
                                </Typography>{" "}
                                <Typography component="span" variant="body2" sx={{ color: "text.secondary", fontWeight: 500 }}>
                                  (Entry: ${entry.toLocaleString("en-GB", { minimumFractionDigits: 2, maximumFractionDigits: 2 })})
                                </Typography>
                              </Typography>
                            );
                          })}
                        </Box>
                      </TableCell>
                      <TableCell>
                        {position.legs.reduce((total, leg) => total + (leg.isLong ? leg.amountToken : -leg.amountToken), 0).toFixed(4)} {getTokenSymbol()}
                      </TableCell>
                      <TableCell sx={{ color: position.currentPnl > 0 ? "#10B981" : position.currentPnl < 0 ? "#EF4444" : "#6B7280", fontWeight: 600 }}>
                        {formatPnlWithSign(position.currentPnl)}
                      </TableCell>
                      <TableCell>
                        SL: ${position.stopLossPrice.toFixed(2)} / TP: ${position.takeProfitPrice.toFixed(2)}
                      </TableCell>
                      <TableCell>
                        <Button
                          variant="contained"
                          size="small"
                          disableElevation
                          onClick={() => setPendingClosePosition(position)}
                          disabled={isCloseProcessing && pendingClosePosition?.positionId === position.positionId}
                          sx={{
                            borderRadius: "8px",
                            px: 2.5,
                            fontWeight: 600,
                            textTransform: "none",
                            color: "#B91C1C",
                            backgroundImage: "linear-gradient(180deg, rgba(254,236,236,.96) 0%, rgba(252,219,219,.96) 100%)",
                            border: "1px solid rgba(248,113,113,.35)",
                            boxShadow: "0px 3px 8px rgba(190,49,68,.16)",
                            "&:hover": {
                              backgroundImage: "linear-gradient(180deg, rgba(253,222,222,1) 0%, rgba(251,209,209,1) 100%)",
                              borderColor: "rgba(220,38,38,.4)",
                              boxShadow: "0px 4px 12px rgba(190,49,68,.18)",
                            },
                            "&:active": {
                              backgroundImage: "linear-gradient(180deg, rgba(252,210,210,1) 0%, rgba(249,196,196,1) 100%)",
                              boxShadow: "0px 2px 6px rgba(190,49,68,.2)",
                            },
                            "&:focus-visible": { outline: "2px solid rgba(244,63,94,.45)", outlineOffset: "2px" },
                          }}
                        >
                          {isCloseProcessing && pendingClosePosition?.positionId === position.positionId ? "Closing..." : TEXT.CLOSE}
                        </Button>
                      </TableCell>
                    </TableRow>
                  )) : (
                    <TableRow>
                      <TableCell colSpan={7} align="center">
                        <Typography variant="body1" sx={{ color: "#6B7280" }}>{TEXT.NO_ACTIVE_POSITIONS}</Typography>
                      </TableCell>
                    </TableRow>
                  )}
                </TableBody>
              </Table>
            </TableContainer>
          </Box>
        </>
      )}

      <ConfirmCloseDialog
        open={Boolean(pendingClosePosition)}
        title="Close position"
        description={
          pendingClosePosition
            ? `Are you sure you want to close position #${pendingClosePosition.positionId} (${getPositionTypeLabel(pendingClosePosition.positionType)})?\nCurrent P/L: ${formatPnlWithSign(pendingClosePosition.currentPnl)}`
            : ""
        }
        confirmLabel="Close position"
        cancelLabel="Keep open"
        onConfirm={handleConfirmClosePosition}
        onCancel={handleCancelClosePosition}
        loading={isCloseProcessing}
      />

      <Snackbar
        open={snackbarOpen}
        autoHideDuration={6000}
        onClose={handleSnackbarClose}
        anchorOrigin={{ vertical: "top", horizontal: "center" }}
      >
        <Alert onClose={handleSnackbarClose} severity="error" sx={{ width: "100%" }}>
          {errorMessage}
        </Alert>
      </Snackbar>
    </Box>
  );
};

export default Dashboard;
