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,
} from "@mui/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;

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

const CopperArbitrum: 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);
      setStatus({ type: "error", message: err?.message || "Failed to connect wallet" });
    }
  }, [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 = err?.error?.message || err?.data?.message || err?.message || "Transaction failed";
      setStatus({ type: "error", message: msg });
    } 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";

  // 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]);

  // -------------------- UI --------------------
  return (
    <Box sx={{ maxWidth: 880, mx: "auto", mt: 6 }}>
      {/* Header / Marketing copy kept simple like original */}
      <Box textAlign="center" sx={{ mb: 3 }}>
        <Typography variant="h4" sx={{ fontWeight: 700 }}>Silver Arbitrum</Typography>
        <Typography color="text.secondary">Buy or Sell IUSD on Arbitrum using USDC, USDT, or DAI.</Typography>
      </Box>

      {!isConnected && (
        <Card sx={{ mb: 3, borderRadius: 3, boxShadow: 2 }}>
          <CardContent>
            <Box display="flex" alignItems="center" justifyContent="space-between" gap={2}>
              <Typography variant="h6">Connect Wallet to Get Started</Typography>
              <Button variant="contained" onClick={connectWallet}>Connect Wallet</Button>
            </Box>
          </CardContent>
        </Card>
      )}

      <Card sx={{ borderRadius: 3, boxShadow: 3 }}>
        <CardHeader
          title={
            <Box display="flex" alignItems="center" justifyContent="space-between" gap={2}>
              <Typography variant="h6">IUSD Exchange</Typography>
              <Button variant="contained" onClick={connectWallet}>
                {isConnected ? shortAddr(userAddress) : "Connect Wallet"}
              </Button>
            </Box>
          }
        />
        <Divider />
        <CardContent>
          {/* Tabs */}
          <Tabs value={mode} onChange={onModeChange} sx={{ mb: 2 }}>
            <Tab value="buy" label="Buy IUSD" />
            <Tab value="sell" label="Sell IUSD" />
          </Tabs>

          {/* Controls */}
          <Box display="grid" gridTemplateColumns={{ xs: "1fr", sm: "1fr 1fr" }} gap={2}>
            <FormControl fullWidth>
              <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"
              inputProps={{ min: 0, step: "any" }}
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              fullWidth
            />
          </Box>

          {/* Balances */}
          <Box display="grid" gridTemplateColumns={{ xs: "1fr", sm: "1fr 1fr" }} gap={2} mt={2}>
            <Box p={2} borderRadius={2} border="1px solid rgba(0,0,0,0.12)">
              <Typography variant="body2" color="text.secondary">IUSD Balance</Typography>
              <Typography variant="h6">{iusdBalance}</Typography>
            </Box>
            <Box p={2} borderRadius={2} border="1px solid rgba(0,0,0,0.12)">
              <Typography variant="body2" color="text.secondary">{stableKey} Balance</Typography>
              <Typography variant="h6">{stableBalance}</Typography>
            </Box>
          </Box>

          {/* Action */}
          <Box mt={3}>
            <Button
              fullWidth
              size="large"
              variant="contained"
              disabled={loading}
              onClick={handleAction}
              endIcon={loading ? <CircularProgress size={20} /> : undefined}
            >
              {mode === "buy" ? "Buy IUSD" : "Sell IUSD"}
            </Button>
          </Box>

          {/* Status Banner */}
          {status && (
            <Alert severity={status.type} sx={{ mt: 2 }}>
              {status.message}
            </Alert>
          )}

          {/* Network notice (no auto-switch; mirrors original behavior) */}
          {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>
    </Box>
  );
};

export default CopperArbitrum;
