import { DynamicContextProvider, useDynamicContext, DynamicUserProfile, DynamicWidget } from '@dynamic-labs/sdk-react-core';
import { EthereumWalletConnectors } from '@dynamic-labs/ethereum';
import { ZeroDevSmartWalletConnectors } from '@dynamic-labs/ethereum-aa';
import { useSbcDynamic } from '@stablecoin.xyz/react';
import { radiusTestnet, TestSBC_CONTRACT_ADDRESS } from '@stablecoin.xyz/core';
import { baseSepolia, base, type Chain } from 'viem/chains';
import { createPublicClient, http, getAddress, parseUnits, encodeFunctionData, erc20Abi } from 'viem';
import { useEffect, useState } from 'react';
import './App.css';

const getChain = () => {
  const chainEnv = import.meta.env.VITE_CHAIN;
  if (chainEnv === 'base') return base;
  if (chainEnv === 'radiusTestnet') return radiusTestnet;
  return baseSepolia;
};

const chain = getChain();
const rpcUrl = import.meta.env.VITE_RPC_URL;

// Radius testnet uses TestSBC (a test token for development)
const TEST_SBC_DECIMALS = 6;

const SBC_TOKEN_ADDRESS = (chain: Chain) => {
  if (chain.id === baseSepolia.id) return '0xf9FB20B8E097904f0aB7d12e9DbeE88f2dcd0F16';
  if (chain.id === base.id) return '0xfdcC3dd6671eaB0709A4C0f3F53De9a333d80798';
  if (chain.id === radiusTestnet.id) return TestSBC_CONTRACT_ADDRESS;
  throw new Error('Unsupported chain');
};

const SBC_DECIMALS = (chain: Chain) => {
  if (chain.id === baseSepolia.id) return 6;
  if (chain.id === base.id) return 18;
  if (chain.id === radiusTestnet.id) return TEST_SBC_DECIMALS;
  throw new Error('Unsupported chain');
};

const getTokenSymbol = (chain: Chain) => {
  if (chain.id === radiusTestnet.id) return 'TestSBC';
  return 'SBC';
};

const chainExplorer = (chain: Chain) => {
  if (chain.id === baseSepolia.id) return 'https://sepolia.basescan.org';
  if (chain.id === base.id) return 'https://basescan.org';
  if (chain.id === radiusTestnet.id) return 'https://testnet.radiustech.xyz/testnet/explorer';
  return '';
};

const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });

// ERC20 + EIP-2612 nonces helper ABI
const erc20PermitAbi = [
  ...erc20Abi,
  {
    "inputs": [
      { "internalType": "address", "name": "owner", "type": "address" }
    ],
    "name": "nonces",
    "outputs": [
      { "internalType": "uint256", "name": "", "type": "uint256" }
    ],
    "stateMutability": "view",
    "type": "function"
  }
] as const;

// Wrapper to render DynamicWidget only after SDK is ready
const DynamicWidgetWrapper = () => {
  const { sdkHasLoaded } = useDynamicContext();
  if (!sdkHasLoaded) return null;
  return <DynamicWidget />;
};

// Wrapper to render DynamicUserProfile only after SDK is ready
const DynamicUserProfileWrapper = () => {
  const { sdkHasLoaded } = useDynamicContext();
  if (!sdkHasLoaded) return null;
  return <DynamicUserProfile />;
};

function WalletStatus() {
  const { primaryWallet } = useDynamicContext();
  const [balances, setBalances] = useState<{ eth: string | null; sbc: string | null }>({ eth: null, sbc: null });

  useEffect(() => {
    if (!primaryWallet?.address) return;
    (async () => {
      try {
        const [ethBalance, sbcBalance] = await Promise.all([
          publicClient.getBalance({ address: primaryWallet.address as `0x${string}` }),
          publicClient.readContract({
            address: SBC_TOKEN_ADDRESS(chain) as `0x${string}`,
            abi: erc20Abi,
            functionName: 'balanceOf',
            args: [primaryWallet.address as `0x${string}`],
          })
        ]);
        setBalances({ eth: ethBalance.toString(), sbc: (sbcBalance as bigint).toString() });
      } catch (error) {
        console.error('Failed to fetch EOA balances:', error);
        setBalances({ eth: null, sbc: null });
      }
    })();
  }, [primaryWallet?.address]);

  if (!primaryWallet) return null;
  const fmtEth = (v: string | null) => v ? (Number(v) / 1e18).toFixed(4) : '0.0000';
  const fmtSbc = (v: string | null) => v ? (Number(v) / Math.pow(10, SBC_DECIMALS(chain))).toFixed(4) : '0.0000';

  return (
    <div className="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg">
      <div className="flex justify-between items-start mb-3">
        <div className="flex-1">
          <h3 className="font-semibold text-green-800 mb-1">✅ Dynamic Wallet Connected</h3>
          <p className="text-xs text-green-600 font-mono break-all mb-2">EOA: {primaryWallet.address}</p>
          <p className="text-xs text-green-600 mb-2">Connected via Dynamic SDK</p>
          <p className="text-xs text-green-600 mb-2"><strong>Chain:</strong> {chain.name} (ID: {chain.id})</p>
          <div className="mt-2 pt-2 border-t border-green-200">
            <p className="text-xs font-medium text-green-700 mb-1">EOA Wallet Balances:</p>
            <div className="flex gap-4">
              <span className="text-xs text-green-600"><strong>ETH:</strong> {fmtEth(balances.eth)}</span>
              <span className="text-xs text-green-600"><strong>{getTokenSymbol(chain)}:</strong> {fmtSbc(balances.sbc)}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SmartAccountInfo({ account, refreshAccount, isLoadingAccount, accountError }: any) {
  const [sbcBalance, setSbcBalance] = useState<string | null>(null);
  useEffect(() => {
    if (!account?.address) return;
    (async () => {
      try {
        const bal = await publicClient.readContract({
          address: SBC_TOKEN_ADDRESS(chain) as `0x${string}`,
          abi: erc20Abi,
          functionName: 'balanceOf',
          args: [account.address as `0x${string}`],
        });
        setSbcBalance((bal as bigint).toString());
      } catch (error) {
        console.error('Failed to fetch smart account SBC balance:', error);
        setSbcBalance('0');
      }
    })();
  }, [account?.address]);

  if (!account) return null;
  const fmtEth = (v: string | null) => v ? (Number(v) / 1e18).toFixed(6) : '0.000000';
  const fmtSbc = (v: string | null) => v ? (Number(v) / Math.pow(10, SBC_DECIMALS(chain))).toFixed(2) : '0.00';

  return (
    <div className="mb-6 p-4 bg-purple-50 border border-purple-200 rounded-lg">
      <div className="flex justify-between items-center mb-2">
        <h3 className="font-semibold text-purple-800">🔐 Smart Account Status</h3>
        <button onClick={refreshAccount} disabled={isLoadingAccount} className="text-xs bg-purple-600 text-white px-3 py-1 rounded hover:bg-purple-700 disabled:opacity-50">{isLoadingAccount ? '🔄 Refreshing...' : '🔄 Refresh'}</button>
      </div>
      <div className="space-y-2 text-sm">
        <div className="flex justify-between"><span className="text-purple-700">Smart Account Address:</span><span className="font-mono text-xs text-purple-600 break-all">{account.address}</span></div>
        <div className="flex justify-between"><span className="text-purple-700">Deployed:</span><span className="text-purple-600">{account.isDeployed ? '✅ Yes' : '⏳ On first transaction'}</span></div>
        <div className="flex justify-between"><span className="text-purple-700">Nonce:</span><span className="text-purple-600">{account.nonce}</span></div>
        <div className="flex justify-between"><span className="text-purple-700">ETH Balance:</span><span className="text-purple-600 font-mono text-xs">{fmtEth(account.balance)} ETH</span></div>
        <div className="flex justify-between"><span className="text-purple-700">{getTokenSymbol(chain)} Balance:</span><span className="text-purple-600 font-mono text-xs">{fmtSbc(sbcBalance)} {getTokenSymbol(chain)}</span></div>
      </div>
      {accountError && <p className="mt-2 text-xs text-red-600">{String(accountError)}</p>}
    </div>
  );
}

function TransactionForm({ account, sbcAppKit }: { account: any; sbcAppKit: any }) {
  const [recipient, setRecipient] = useState('');
  const [amount, setAmount] = useState('1');
  const [status, setStatus] = useState<'idle'|'loading'|'success'|'error'>('idle');
  const [error, setError] = useState<string | null>(null);
  const [result, setResult] = useState<any>(null);
  const isValid = recipient && /^0x[a-fA-F0-9]{40}$/.test(recipient) && parseFloat(amount) > 0;

  const sendTx = async () => {
    if (!isValid || !account || !sbcAppKit) return;
    try {
      setStatus('loading'); setError(null);
      const owner = sbcAppKit.getOwnerAddress();
      const value = parseUnits(amount, SBC_DECIMALS(chain));
      const deadline = Math.floor(Date.now() / 1000) + 60 * 30;
      const { publicClient: pc, walletClient: wc } = (sbcAppKit as any);
      const [nonce, tokenName] = await Promise.all([
        pc.readContract({ address: SBC_TOKEN_ADDRESS(chain) as `0x${string}`, abi: erc20PermitAbi, functionName: 'nonces', args: [owner] }),
        pc.readContract({ address: SBC_TOKEN_ADDRESS(chain), abi: erc20Abi, functionName: 'name' })
      ]);
      const domain = { name: tokenName as string, version: '1', chainId: chain.id, verifyingContract: SBC_TOKEN_ADDRESS(chain) };
      const types = { Permit: [
        { name: 'owner', type: 'address' },
        { name: 'spender', type: 'address' },
        { name: 'value', type: 'uint256' },
        { name: 'nonce', type: 'uint256' },
        { name: 'deadline', type: 'uint256' },
      ] } as const;
      const message = { owner, spender: account.address, value, nonce, deadline: BigInt(deadline) } as const;
      const signature = await wc.signTypedData({ domain, types, primaryType: 'Permit', message });
      const { r, s, v } = (await import('viem')).parseSignature(signature);
      const permitData = encodeFunctionData({
        abi: [{ name: 'permit', type: 'function', inputs: [
          { name: 'owner', type: 'address' },
          { name: 'spender', type: 'address' },
          { name: 'value', type: 'uint256' },
          { name: 'deadline', type: 'uint256' },
          { name: 'v', type: 'uint8' },
          { name: 'r', type: 'bytes32' },
          { name: 's', type: 'bytes32' }
        ] }],
        functionName: 'permit',
        args: [owner, account.address, value, BigInt(deadline), v, r, s]
      });
      const transferFromData = encodeFunctionData({
        abi: erc20Abi,
        functionName: 'transferFrom',
        args: [owner, recipient as `0x${string}`, value]
      });
      const res = await sbcAppKit.sendUserOperation({
        calls: [
          { to: SBC_TOKEN_ADDRESS(chain) as `0x${string}`, data: permitData },
          { to: SBC_TOKEN_ADDRESS(chain) as `0x${string}`, data: transferFromData }
        ]
      });
      setResult(res);
      setStatus('success');
    } catch (e: any) {
      setError(e?.message || 'Transaction failed');
      setStatus('error');
    }
  };

  if (!account) return null;

  return (
    <div className="p-4 bg-white border border-gray-200 rounded-lg shadow-sm">
      <h3 className="font-semibold text-gray-800 mb-4">💸 Send {getTokenSymbol(chain)} Tokens</h3>
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">Recipient Address</label>
          <input type="text" value={recipient} onChange={(e) => setRecipient(e.target.value)} placeholder="0x..." className="w-full px-3 py-2 text-xs font-mono border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 border-gray-300" />
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">Amount ({getTokenSymbol(chain)})</label>
          <input type="number" value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="1.0" step="0.000001" min="0" className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 border-gray-300" />
        </div>
        <div className="p-3 bg-gray-50 rounded">
          <div className="flex justify-between text-sm"><span>Amount:</span><span className="font-medium">{amount} {getTokenSymbol(chain)}</span></div>
          <div className="flex justify-between text-xs text-gray-600"><span>Gas fees:</span><span>Covered by SBC Paymaster ✨</span></div>
          <div className="flex justify-between text-xs text-gray-600"><span>Signing:</span><span>Your Dynamic wallet will prompt to sign 🖊️</span></div>
        </div>
        <button onClick={sendTx} disabled={!isValid || status==='loading' || !account} className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed">
          {status==='loading' ? 'Waiting for signature...' : `Send ${amount} ${getTokenSymbol(chain)}`}
        </button>
        {status==='success' && result && (
          <div className="p-3 bg-green-50 border border-green-200 rounded">
            <p className="text-sm text-green-800 font-medium">✅ Transaction Submitted</p>
            <p className="text-xs text-green-600 font-mono break-all mt-1">
              <a href={`${chainExplorer(chain)}/tx/${result.transactionHash}`} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">View transaction: {result.transactionHash}</a>
            </p>
          </div>
        )}
        {status==='error' && error && (
          <div className="p-3 bg-red-50 border border-red-200 rounded">
            <p className="text-sm text-red-800 font-medium">❌ Transaction Failed</p>
            <p className="text-xs text-red-600 mt-1">{error}</p>
          </div>
        )}
      </div>
    </div>
  );
}

function DynamicApp() {
  const { primaryWallet } = useDynamicContext();
  const { sbcAppKit, isInitialized, error, account, isLoadingAccount, accountError, refreshAccount } = useSbcDynamic({
    apiKey: import.meta.env.VITE_SBC_API_KEY,
    chain,
    primaryWallet,
    rpcUrl,
    debug: true
  });

  return (
    <>
      <div className="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
        <h3 className="font-semibold text-blue-800 mb-2">🔗 Connect to Dynamic</h3>
        <p className="text-sm text-blue-600 mb-3">
          Connect your wallet or sign in with email to create a smart account with Dynamic
        </p>
        <DynamicWidgetWrapper />
      </div>
      {primaryWallet && isInitialized && (
        <>
          <WalletStatus />
          <SmartAccountInfo account={account} refreshAccount={refreshAccount} isLoadingAccount={isLoadingAccount} accountError={accountError} />
          <TransactionForm account={account} sbcAppKit={sbcAppKit} />
        </>
      )}
      {error && <div className="error">{error.message}</div>}
    </>
  );
}

export default function App() {
  return (
    <DynamicContextProvider
      settings={{
        environmentId: import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID || '',
        walletConnectors: [EthereumWalletConnectors, ZeroDevSmartWalletConnectors],
      }}
    >
      <div className="min-h-screen bg-gray-50 py-8">
        <div className="max-w-2xl mx-auto px-4">
          <div className="text-center mb-8">
            <h1 className="text-3xl font-bold text-gray-900 mb-2 flex items-center justify-center gap-3">
              <img src="/sbc-logo.png" alt="SBC Logo" width={36} height={36} />
              SBC (Dynamic) Integration
            </h1>
            <p className="text-gray-600">Gasless transactions with Dynamic SDK integration</p>
          </div>

          <DynamicApp />

          <DynamicUserProfileWrapper />

          <div className="mt-8 text-center text-xs text-gray-500">
            <p>
              Powered by{' '}
              <a href="https://github.com/stablecoinxyz/app-kit" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">SBC AppKit</a>
              {' '}• Dynamic SDK integration
            </p>
          </div>
        </div>
      </div>
    </DynamicContextProvider>
  );
}


