// Real wallet connect + SIWE-style sign-in, backed by /api/auth/*.
const WalletContext = React.createContext({
  address: null,
  isAdmin: false,
  connecting: false,
  error: null,
  chainConfig: null,
  connect: async () => {},
  disconnect: async () => {},
  getSigner: async () => null,
  ensureContractNetwork: async () => {},
});

function WalletProvider({ children }) {
  const [address, setAddress] = React.useState(null);
  const [isAdmin, setIsAdmin] = React.useState(false);
  const [connecting, setConnecting] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [chainConfig, setChainConfig] = React.useState(null);

  React.useEffect(() => {
    fetch('/api/chain').then((r) => r.json()).then(setChainConfig).catch(() => setChainConfig({ configured: false }));
    fetch('/api/auth/me', { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => { setAddress(d.address); setIsAdmin(Boolean(d.isAdmin)); })
      .catch(() => {});
  }, []);

  React.useEffect(() => {
    if (!window.ethereum) return;
    const onAccountsChanged = () => {
      setAddress(null);
      setIsAdmin(false);
      fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }).catch(() => {});
    };
    window.ethereum.on('accountsChanged', onAccountsChanged);
    return () => window.ethereum.removeListener('accountsChanged', onAccountsChanged);
  }, []);

  async function connect() {
    setError(null);
    if (!window.ethereum) {
      setError('No wallet found. Install MetaMask (or another injected wallet) to continue.');
      return;
    }
    setConnecting(true);
    try {
      const provider = new window.ethers.BrowserProvider(window.ethereum);
      const accounts = await provider.send('eth_requestAccounts', []);
      const walletAddress = accounts[0];

      const nonceRes = await fetch('/api/auth/nonce', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ address: walletAddress }),
      });
      const nonceBody = await nonceRes.json();
      if (!nonceRes.ok) throw new Error(nonceBody.error || 'Could not start sign-in.');

      const signer = await provider.getSigner();
      const signature = await signer.signMessage(nonceBody.message);

      const verifyRes = await fetch('/api/auth/verify', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ message: nonceBody.message, signature }),
      });
      const verifyBody = await verifyRes.json();
      if (!verifyRes.ok) throw new Error(verifyBody.error || 'Sign-in failed.');
      setAddress(verifyBody.address);
      setIsAdmin(Boolean(verifyBody.isAdmin));
    } catch (e) {
      setError(e && e.message ? e.message : String(e));
    } finally {
      setConnecting(false);
    }
  }

  async function disconnect() {
    await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }).catch(() => {});
    setAddress(null);
    setIsAdmin(false);
  }

  async function getSigner() {
    if (!window.ethereum) return null;
    const provider = new window.ethers.BrowserProvider(window.ethereum);
    return provider.getSigner();
  }

  // Prompts the wallet to switch to (or add) whatever chain the backend's
  // deployed contract actually lives on — keeps the frontend from hardcoding
  // a chain id that only matches one specific deployment.
  async function ensureContractNetwork() {
    if (!chainConfig || !chainConfig.configured) {
      throw new Error('Chain is not configured on the server yet — deploy the contract first.');
    }
    const targetHex = '0x' + chainConfig.chainId.toString(16);
    const current = await window.ethereum.request({ method: 'eth_chainId' });
    if (current === targetHex) return;
    try {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: targetHex }],
      });
    } catch (switchError) {
      if (switchError && switchError.code === 4902) {
        await window.ethereum.request({
          method: 'wallet_addEthereumChain',
          params: [
            {
              chainId: targetHex,
              chainName: chainConfig.chainId === 80002 ? 'Polygon Amoy Testnet' : `Local chain ${chainConfig.chainId}`,
              nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
              // Route through this app's own /rpc proxy rather than the server's
              // internal RPC_URL directly — the wallet runs in the user's own
              // browser, which can only reach this origin (wherever it actually
              // loaded the page from), never the server's private/internal
              // network address (e.g. http://127.0.0.1:8545 means the user's
              // own machine, not the server's).
              rpcUrls: [window.location.origin + '/rpc'],
              blockExplorerUrls: chainConfig.chainId === 80002 ? ['https://amoy.polygonscan.com'] : [],
            },
          ],
        });
      } else {
        throw switchError;
      }
    }
  }

  return (
    <WalletContext.Provider value={{ address, isAdmin, connecting, error, chainConfig, connect, disconnect, getSigner, ensureContractNetwork }}>
      {children}
    </WalletContext.Provider>
  );
}

function useWallet() {
  return React.useContext(WalletContext);
}

window.WalletProvider = WalletProvider;
window.useWallet = useWallet;
