import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
  Alert,
  Box,
  Button,
  Card,
  CardContent,
  CardHeader,
  Divider,
  FormControl,
  InputLabel,
  MenuItem,
  Select,
  SelectChangeEvent,
  Tab,
  Tabs,
  TextField,
  Typography,
  CircularProgress,
  Chip,
  Snackbar,
} from "@mui/material";
import { Logout as LogoutIcon } from "@mui/icons-material";
import { BrowserProvider, Contract, Eip1193Provider, MaxUint256, formatUnits, parseUnits, ethers } from "ethers";
import { ARBITRUM_IUSD_STABLES,SILVER_IUSD_EXCHANGE_ABI,SILVER_IUSED_ERC20_ABI,ARBITRUM_IUSD_EXCHANGE_ADDRESS, ARBITRUM_IUSD_TOKEN_ADDRESS  } from "../../const";


const ARBITRUM_CHAIN_ID_DEC = 42161; // 0xA4B1

const EXCHANGE_ADDRESS = ARBITRUM_IUSD_EXCHANGE_ADDRESS
const IUSD_ADDRESS = ARBITRUM_IUSD_TOKEN_ADDRESS

const STABLES = ARBITRUM_IUSD_STABLES;

type StableKey = keyof typeof STABLES; // 'USDC' | 'USDT' | 'DAI'

// Minimal ERC-20 ABI for what we use
const ERC20_ABI = SILVER_IUSED_ERC20_ABI

// Minimal Exchange ABI — only functions used by UI
const EXCHANGE_ABI = SILVER_IUSD_EXCHANGE_ABI

type Mode = "buy" | "sell";

// Local helper to safely access window.ethereum without global augmentation
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 (align with IntelliTradeGold concise errors)
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"));
};

const shortAddr = (addr: string) => `${addr.slice(0, 6)}…${addr.slice(-4)}`;

const Arbitrum: React.FC = () => {
  // -------------------- State --------------------
  const [mode, setMode] = useState<Mode>("buy");
  const [stableKey, setStableKey] = useState<StableKey>("USDC");
  const [amount, setAmount] = useState<string>("");

  const [provider, setProvider] = useState<BrowserProvider | null>(null);
  const [signer, setSigner] = useState<ethers.Signer | null>(null);
  const [userAddress, setUserAddress] = useState<string>("");
  const [chainId, setChainId] = useState<number | null>(null);

  const [status, setStatus] = useState<null | { type: "info" | "success" | "error"; message: string }>(null);
  const [loading, setLoading] = useState<boolean>(false);

  // -------------------- Contracts --------------------
  const exchangeContract = useMemo(() => {
    if (!signer) return null;
    return new Contract(EXCHANGE_ADDRESS, EXCHANGE_ABI, signer);
  }, [signer]);

  const iusdContract = useMemo(() => {
    if (!signer) return null;
    return new Contract(IUSD_ADDRESS, ERC20_ABI, signer);
  }, [signer]);

  const activeStable = STABLES[stableKey];

  const activeStableContract = useMemo(() => {
    if (!signer) return null;
    return new Contract(activeStable.address, ERC20_ABI, signer);
  }, [signer, activeStable.address]);

  // -------------------- Balances --------------------
  const [iusdBalance, setIusdBalance] = useState<string>("0.0000");
  const [stableBalance, setStableBalance] = useState<string>("0.0000");

  const refreshBalances = useCallback(async () => {
    try {
      if (!userAddress || !iusdContract || !activeStableContract) return;
      const [iusdDec, stableDec] = await Promise.all([
        iusdContract.decimals(),
        activeStableContract.decimals(),
      ]);
      const [rawIusd, rawStable] = await Promise.all([
        iusdContract.balanceOf(userAddress),
        activeStableContract.balanceOf(userAddress),
      ]);
      setIusdBalance(Number(formatUnits(rawIusd, iusdDec)).toFixed(4));
      setStableBalance(Number(formatUnits(rawStable, stableDec)).toFixed(4));
    } catch (err: any) {
      console.error(err);
      setStatus({ type: "error", message: err?.message || "Failed to fetch balances" });
    }
  }, [userAddress, iusdContract, activeStableContract]);

  useEffect(() => {
    const eth = getEthereum();
    if (!eth) return;
    (async () => {
      try {
        const web3 = new BrowserProvider(eth as Eip1193Provider);
        const accounts = await web3.listAccounts();
        const network = await web3.getNetwork();
        setChainId(Number(network.chainId));
        if (accounts.length > 0) {
          setProvider(web3);
          const s = await web3.getSigner();
          setSigner(s);
          setUserAddress(await s.getAddress());
        }
      } catch (_) {}
    })();
  }, []);

  useEffect(() => {
    if (userAddress) void refreshBalances();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [userAddress, stableKey]);

  // -------------------- Actions --------------------
  const connectWallet = useCallback(async () => {
    const eth = getEthereum();
    if (!eth) {
      setStatus({ type: "error", message: "MetaMask not detected. Please install MetaMask and try again." });
      return;
    }
    try {
      const web3 = new BrowserProvider(eth as Eip1193Provider);
      await web3.send("eth_requestAccounts", []);
      const network = await web3.getNetwork();
      setChainId(Number(network.chainId));
      const s = await web3.getSigner();
      setProvider(web3);
      setSigner(s);
      setUserAddress(await s.getAddress());
      if (Number(network.chainId) !== ARBITRUM_CHAIN_ID_DEC) {
        setStatus({ type: "error", message: "Please switch your wallet to Arbitrum One (chainId 42161)." });
      } else {
        setStatus({ type: "success", message: "Wallet connected." });
        await refreshBalances();
      }
    } catch (err: any) {
      console.error(err);
      const msg = extractErrorMessage(err);
      const lower = (msg || "").toLowerCase();
      const isRejected = err?.code === 4001 || lower.includes("user rejected") || lower.includes("action_rejected") || lower.includes("request rejected") || lower.includes("rejected transaction") || lower.includes("rejected");
      const concise = isRejected
        ? "Transaction error: rejected"
        : lower.includes("no matching fragment")
        ? "Error: Net short positions are not supported. Total long amount must be >= total short amount."
        : containsExecutionReverted(err, msg)
        ? "Transaction error: execution reverted"
        : (msg || "Action failed");
      setStatus({ type: "error", message: concise });
    }
  }, [refreshBalances]);

  const onModeChange = (_: React.SyntheticEvent, newMode: Mode) => {
    setMode(newMode);
    setAmount("");
  };

  const onStableChange = (e: SelectChangeEvent<StableKey>) => {
    setStableKey(e.target.value as StableKey);
  };

  const handleAction = useCallback(async () => {
    if (!signer || !exchangeContract || !activeStableContract || !iusdContract) {
      setStatus({ type: "error", message: "Connect your wallet first." });
      return;
    }
    if (chainId !== ARBITRUM_CHAIN_ID_DEC) {
      setStatus({ type: "error", message: "Please switch to Arbitrum One (42161)." });
      return;
    }

    const amt = parseFloat(amount);
    if (!amount || isNaN(amt) || amt <= 0) {
      setStatus({ type: "error", message: "Enter a valid amount greater than 0." });
      return;
    }

    try {
      setLoading(true);
      setStatus({ type: "info", message: "1/2 Checking allowance…" });

      // Which token is being spent?
      const tokenToSpend = mode === "buy" ? activeStableContract : iusdContract;
      const tokenDecimals: number = await tokenToSpend.decimals();
      const amountIn = parseUnits(amount, tokenDecimals);

      const owner = userAddress;
      const spender = EXCHANGE_ADDRESS;
      const allowance = await tokenToSpend.allowance(owner, spender);

      if (allowance < amountIn) {
        const approveTx = await tokenToSpend.approve(spender, MaxUint256);
        await approveTx.wait();
      }

      setStatus({ type: "info", message: "2/2 Submitting transaction…" });

      if (mode === "buy") {
        const tx = await exchangeContract.buyIUSD(activeStable.address, amountIn);
        await tx.wait();
      } else {
        const tx = await exchangeContract.sellIUSD(activeStable.address, amountIn);
        await tx.wait();
      }

      setAmount("");
      await refreshBalances();
      setStatus({ type: "success", message: "Swap successful!" });
    } catch (err: any) {
      console.error(err);
      const msg = extractErrorMessage(err);
      const lower = (msg || "").toLowerCase();
      const isRejected = err?.code === 4001 || lower.includes("user rejected") || lower.includes("action_rejected") || lower.includes("request rejected") || lower.includes("rejected transaction") || lower.includes("rejected");
      const concise = isRejected
        ? "Transaction error : rejected"
        : lower.includes("no matching fragment")
        ? "Error: Net short positions are not supported. Total long amount must be >= total short amount."
        : containsExecutionReverted(err, msg)
        ? "Transaction error: execution reverted"
        : (msg || "Action failed");
      setStatus({ type: "error", message: concise });
    } finally {
      setLoading(false);
    }
  }, [signer, exchangeContract, activeStableContract, iusdContract, chainId, amount, mode, activeStable.address, userAddress, refreshBalances]);

  const isConnected = Boolean(signer && userAddress);
  const amountLabel = mode === "buy" ? `Amount of ${stableKey} to Spend` : "Amount of IUSD to Sell";
  const connectionLabel = isConnected ? `Connected: ${shortAddr(userAddress)}` : "Not Connected";
  const [snackbarOpen, setSnackbarOpen] = useState(false);

  useEffect(() => {
    if (status?.message) {
      setSnackbarOpen(true);
    }
  }, [status]);

  const handleSnackbarClose = () => setSnackbarOpen(false);

  const handleDisconnect = () => {
    // UI-only disconnect: clear local connection state
    setProvider(null);
    setSigner(null);
    setUserAddress("");
    setStatus({ type: "info", message: "Wallet disconnected." });
  };

  // Sync on account or chain changes
  useEffect(() => {
    const eth = getEthereum();
    if (!eth) return;
    const handleAccountsChanged = (accounts: string[]) => {
      if (!accounts || accounts.length === 0) {
        setProvider(null);
        setSigner(null);
        setUserAddress("");
        setStatus({ type: "info", message: "Wallet disconnected." });
      } else {
        void (async () => { await connectWallet(); })();
      }
    };
    const handleChainChanged = () => { void (async () => { await connectWallet(); })(); };
    try {
      eth.on?.("accountsChanged", handleAccountsChanged);
      (eth as any)?.on?.("chainChanged", handleChainChanged as any);
    } catch (_) {}
    return () => {
      try {
        eth?.removeListener?.("accountsChanged", handleAccountsChanged);
        (eth as any)?.removeListener?.("chainChanged", handleChainChanged as any);
      } catch (_) {}
    };
  }, [connectWallet]);

return (
  <Box sx={{ maxWidth: 880, mx: "auto", py: { xs: 3, md: 5 } }}>
    <Card elevation={1} sx={{border: "1px solid #D4DBE3", boxShadow: "none"}}>
      {/* Header */}
      <CardHeader
        title={
          <Box>
            <Typography variant="h5" fontWeight={700} lineHeight={1.3}>
              IUSD Exchange Arbitrum
            </Typography>
            <Typography variant="subtitle1" fontWeight={600}>
              Buy IUSD Tokens
            </Typography>
            <Typography variant="body2" color="text.secondary">
              Exchange your stablecoins for IUSD tokens securely on the Arbitrum network.
            </Typography>
          </Box>
        }
        action={
          <Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
            <Chip
              label={connectionLabel}
              color={isConnected ? "success" : "default"}
              sx={{ fontWeight: 500 }}
              aria-label={`Connection status: ${connectionLabel}`}
            />
            {!isConnected ? (
              <Button variant="contained" onClick={connectWallet} aria-label="Connect wallet">
                {loading ? <CircularProgress size={20} color="inherit" /> : "Connect Wallet"}
              </Button>
            ) : (
              <Button variant="outlined" startIcon={<LogoutIcon />} onClick={handleDisconnect} aria-label="Disconnect wallet">
                Disconnect
              </Button>
            )}
          </Box>
        }
        sx={{ pb: 0 }}
      />

      <CardContent sx={{ pt: 2 }}>
        {/* Tabs */}
        <Tabs
          value={mode}
          onChange={onModeChange}
          variant="fullWidth"
          sx={{
            mb: 2,
            ".MuiTabs-indicator": { height: 3, borderRadius: 1 },
            ".MuiTab-root": { fontWeight: 600 },
          }}
        >
          <Tab value="buy" label="Buy IUSD" />
          <Tab value="sell" label="Sell IUSD" />
        </Tabs>

        {/* Inputs row (no Grid) */}
        <Box
          sx={{
            display: "flex",
            flexDirection: { xs: "column", sm: "row" },
            gap: 2,
          }}
        >
          <FormControl fullWidth size="small">
            <InputLabel id="stable-label">Stablecoin</InputLabel>
            <Select<StableKey>
              labelId="stable-label"
              label="Stablecoin"
              value={stableKey}
              onChange={onStableChange}
            >
              {(Object.keys(STABLES) as StableKey[]).map((k) => (
                <MenuItem key={k} value={k}>
                  {k}
                </MenuItem>
              ))}
            </Select>
          </FormControl>

          <TextField
            label={amountLabel}
            type="number"
            size="small"
            inputProps={{ min: 0, step: "any", inputMode: "decimal" }}
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            fullWidth
          />
        </Box>

        {/* Balances row (no Grid) */}
        <Box
          sx={{
            mt: 2,
            display: "flex",
            flexDirection: { xs: "column", sm: "row" },
            gap: 2,
          }}
        >
          <Box
            sx={{
              flex: 1,
              p: 2,
              borderRadius: 2,
              border: 1,
              borderColor: "divider",
            }}
          >
            <Typography variant="caption" color="text.secondary">
              IUSD Balance
            </Typography>
            <Typography variant="h6" sx={{ mt: 0.5 }}>
              {iusdBalance}
            </Typography>
          </Box>

          <Box
            sx={{
              flex: 1,
              p: 2,
              borderRadius: 2,
              border: 1,
              borderColor: "divider",
            }}
          >
            <Typography variant="caption" color="text.secondary">
              {stableKey} Balance
            </Typography>
            <Typography variant="h6" sx={{ mt: 0.5 }}>
              {stableBalance}
            </Typography>
          </Box>
        </Box>

        <Divider sx={{ my: 3 }} />

        <Button
          fullWidth
          size="large"
          variant="contained"
          disabled={loading}
          onClick={handleAction}
          endIcon={loading ? <CircularProgress size={20} /> : undefined}
          sx={{ py: 1.2, fontWeight: 700 }}
        >
          {mode === "buy" ? "Buy IUSD" : "Sell IUSD"}
        </Button>
        {isConnected && chainId !== ARBITRUM_CHAIN_ID_DEC && (
          <Alert severity="warning" sx={{ mt: 2 }}>
            You are not on Arbitrum One (42161). Please switch networks in your wallet.
          </Alert>
        )}
      </CardContent>
    </Card>
    {status && (
      <Snackbar
        open={snackbarOpen}
        autoHideDuration={status?.type === "error" ? 8000 : 4000}
        onClose={handleSnackbarClose}
        anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
      >
        <Alert onClose={handleSnackbarClose} severity={status.type} sx={{ width: "100%" }}>
          {status.message}
        </Alert>
      </Snackbar>
    )}
  </Box>
);


};

export default Arbitrum;
