"use client";

import { useEffect, useMemo, useState } from "react";
import {
  createPublicClient,
  http,
  type Address,
  type Hash,
  encodeAbiParameters,
  formatEther,
} from "viem";
import { base, mainnet } from "viem/chains";
import artifact from "../lib/genesis/artifact.json";
import create2 from "../lib/genesis/create2.json";

// Lock-down: only this wallet is allowed to mint.
const ALLOWED_WALLET: Address = "0xfA15Ee28939B222B0448261A22156070f0A7813C";
const ALLOWED_VNS = "ghostkey.base.eth";

const TOKEN_URI = "https://theloopbreaker.com/nft/vaultfire-genesis.json";
const IMG = "/nft/vaultfire-genesis.png";

// Arachnid CREATE2 factory — exists at the same address on every EVM chain.
// We route deploys through it because Base App / Coinbase Smart Wallet does NOT
// support raw `to: null` contract-creation transactions. By calling the factory
// (a normal `to: factory` tx), the deploy works through any wallet.
const FACTORY: Address = "0x4e59b44847b379578588920ca78fbf26c0b4956c";
const SALT = create2.genesis.salt as `0x${string}`;
const PREDICTED: Address = create2.genesis.predicted as Address;

const basePublic = createPublicClient({ chain: base, transport: http() });
// ENS reverse lookup happens on Ethereum mainnet
const ethPublic = createPublicClient({ chain: mainnet, transport: http() });

type Status =
  | { kind: "idle" }
  | { kind: "checking" }
  | { kind: "ready" }
  | { kind: "deploying"; hash?: Hash }
  | { kind: "deployed"; hash: Hash; address: Address }
  | { kind: "already-deployed"; address: Address }
  | { kind: "error"; message: string };

export default function MintGenesisPage() {
  const [account, setAccount] = useState<Address | null>(null);
  const [chainId, setChainId] = useState<number | null>(null);
  const [ensName, setEnsName] = useState<string | null>(null);
  const [balance, setBalance] = useState<string | null>(null);
  const [status, setStatus] = useState<Status>({ kind: "idle" });

  const isAllowed = useMemo(() => {
    if (!account) return false;
    return account.toLowerCase() === ALLOWED_WALLET.toLowerCase();
  }, [account]);

  const onBase = chainId === base.id;

  useEffect(() => {
    if (typeof window === "undefined") return;
    const eth = (window as any).ethereum;
    if (!eth) return;
    const refresh = async () => {
      try {
        const accs: string[] = await eth.request({ method: "eth_accounts" });
        if (accs && accs[0]) setAccount(accs[0] as Address);
        const cid: string = await eth.request({ method: "eth_chainId" });
        setChainId(parseInt(cid, 16));
      } catch {}
    };
    refresh();
    const onAcc = (accs: string[]) => setAccount(accs[0] ? (accs[0] as Address) : null);
    const onChain = (cid: string) => setChainId(parseInt(cid, 16));
    eth.on?.("accountsChanged", onAcc);
    eth.on?.("chainChanged", onChain);
    return () => {
      eth.removeListener?.("accountsChanged", onAcc);
      eth.removeListener?.("chainChanged", onChain);
    };
  }, []);

  useEffect(() => {
    if (!account) {
      setEnsName(null);
      setBalance(null);
      return;
    }
    (async () => {
      try {
        const name = await ethPublic.getEnsName({ address: account });
        setEnsName(name ?? null);
      } catch {
        setEnsName(null);
      }
      try {
        const bal = await basePublic.getBalance({ address: account });
        setBalance(formatEther(bal));
      } catch {}
    })();
  }, [account]);

  async function connect() {
    const eth = (window as any).ethereum;
    if (!eth) {
      setStatus({ kind: "error", message: "No wallet detected. Open this page in Base App or Coinbase Wallet." });
      return;
    }
    try {
      const accs: string[] = await eth.request({ method: "eth_requestAccounts" });
      setAccount(accs[0] as Address);
      const cid: string = await eth.request({ method: "eth_chainId" });
      setChainId(parseInt(cid, 16));
    } catch (e: any) {
      setStatus({ kind: "error", message: e?.message ?? "Connect rejected" });
    }
  }

  async function switchToBase() {
    const eth = (window as any).ethereum;
    try {
      await eth.request({
        method: "wallet_switchEthereumChain",
        params: [{ chainId: "0x2105" }], // 8453
      });
    } catch (e: any) {
      // Add chain if not present
      if (e?.code === 4902) {
        await eth.request({
          method: "wallet_addEthereumChain",
          params: [{
            chainId: "0x2105",
            chainName: "Base",
            nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
            rpcUrls: ["https://mainnet.base.org"],
            blockExplorerUrls: ["https://basescan.org"],
          }],
        });
      } else {
        setStatus({ kind: "error", message: e?.message ?? "Failed to switch network" });
      }
    }
  }

  async function deployAndMint() {
    if (!account || !isAllowed) return;
    if (!onBase) {
      await switchToBase();
      return;
    }
    setStatus({ kind: "deploying" });

    try {
      // Short-circuit: if a contract already lives at PREDICTED, the deploy is
      // already done. Just show the address.
      const existingCode = await basePublic.getBytecode({ address: PREDICTED });
      if (existingCode && existingCode !== "0x") {
        setStatus({ kind: "already-deployed", address: PREDICTED });
        return;
      }

      // Build CREATE2 calldata: salt(32) ++ initcode
      // initcode = bytecode ++ abi.encode(constructor args)
      const ctorArgs = encodeAbiParameters(
        [
          { type: "address", name: "recipient_" },
          { type: "string", name: "tokenURI_" },
        ],
        [ALLOWED_WALLET, TOKEN_URI],
      );
      const initcode = (artifact.bytecode + ctorArgs.slice(2)) as `0x${string}`;
      const calldata = (SALT + initcode.slice(2)) as `0x${string}`;

      // Submit minimal tx params — let Base App estimate gas/fees itself.
      // Passing explicit gas/fee fields can cause Base App's review screen
      // to hang on Confirm.
      const eth = (window as any).ethereum;
      const hash: Hash = await eth.request({
        method: "eth_sendTransaction",
        params: [{
          from: account,
          to: FACTORY,
          data: calldata,
          value: "0x0",
        }],
      });
      setStatus({ kind: "deploying", hash });

      const receipt = await basePublic.waitForTransactionReceipt({ hash });
      if (receipt.status !== "success") {
        throw new Error(`Tx ${hash} reverted on-chain.`);
      }

      // The receipt won't carry contractAddress (the outer tx targets the
      // factory, not a creation). Verify the predicted address now has code.
      const code = await basePublic.getBytecode({ address: PREDICTED });
      if (!code || code === "0x") {
        throw new Error(`Tx mined but no code at ${PREDICTED} — deploy did not land.`);
      }
      setStatus({ kind: "deployed", hash, address: PREDICTED });
    } catch (e: any) {
      setStatus({ kind: "error", message: e?.shortMessage ?? e?.message ?? "Deploy failed" });
    }
  }

  return (
    <div style={styles.page}>
      <div style={styles.card}>
        <header style={styles.header}>
          <div style={styles.kicker}>VAULTFIRE</div>
          <h1 style={styles.title}>Genesis Mint</h1>
          <p style={styles.lead}>
            One-of-one ERC-721 commemorating Vaultfire — KYA Trust Infrastructure for AI Agents.
            Auto-mints token #1 to the deployer. Restricted to{" "}
            <code style={styles.code}>{ALLOWED_VNS}</code>.
          </p>
        </header>

        <div style={styles.previewWrap}>
          <img src={IMG} alt="Vaultfire Genesis" style={styles.preview} />
        </div>

        <dl style={styles.grid}>
          <dt style={styles.dt}>Standard</dt><dd style={styles.dd}>ERC-721 (1 of 1)</dd>
          <dt style={styles.dt}>Chain</dt><dd style={styles.dd}>Base · 8453</dd>
          <dt style={styles.dt}>Predicted address</dt>
          <dd style={styles.dd}><code style={styles.code}>{PREDICTED}</code></dd>
          <dt style={styles.dt}>Token URI</dt>
          <dd style={styles.dd}>
            <a href={TOKEN_URI} style={styles.link} target="_blank" rel="noreferrer">{TOKEN_URI}</a>
          </dd>
          <dt style={styles.dt}>Allowed wallet</dt>
          <dd style={styles.dd}><code style={styles.code}>{ALLOWED_VNS}</code></dd>
          <dt style={styles.dt}>License</dt><dd style={styles.dd}>MIT, no token, solo-built</dd>
        </dl>

        <section style={styles.section}>
          {!account ? (
            <button onClick={connect} style={styles.btnPrimary}>Connect wallet</button>
          ) : (
            <>
              <div style={styles.statusRow}>
                <div>
                  <div style={styles.muted}>Connected</div>
                  <div style={styles.mono}>
                    {account}
                    {ensName ? <span style={styles.ens}> · {ensName}</span> : null}
                  </div>
                  <div style={styles.muted}>
                    {onBase ? "Base · ETH " : `Chain ${chainId} · `}
                    {balance ? `${Number(balance).toFixed(5)} ETH` : ""}
                  </div>
                </div>
              </div>

              {!isAllowed && (
                <div style={styles.alertBad}>
                  This wallet is not authorized. Connect <code>{ALLOWED_VNS}</code> to mint.
                </div>
              )}

              {isAllowed && !onBase && (
                <button onClick={switchToBase} style={styles.btnPrimary}>
                  Switch to Base
                </button>
              )}

              {isAllowed && onBase && status.kind !== "deployed" && status.kind !== "already-deployed" && (
                <button
                  onClick={() => deployAndMint()}
                  disabled={status.kind === "deploying"}
                  style={status.kind === "deploying" ? styles.btnDisabled : styles.btnPrimary}
                >
                  {status.kind === "deploying" ? "Deploying\u2026" : "Deploy + mint #1"}
                </button>
              )}

              {status.kind === "deploying" && status.hash && (
                <div style={styles.alertInfo}>
                  Tx submitted:{" "}
                  <a style={styles.link} target="_blank" rel="noreferrer"
                     href={`https://basescan.org/tx/${status.hash}`}>{status.hash.slice(0, 18)}…</a>
                </div>
              )}

              {status.kind === "deployed" && (
                <div style={styles.alertGood}>
                  <div style={{ fontWeight: 700, marginBottom: 6 }}>Minted.</div>
                  <div style={styles.mono}>{status.address}</div>
                  <div style={{ marginTop: 10, display: "flex", gap: 12, flexWrap: "wrap" }}>
                    <a style={styles.link} target="_blank" rel="noreferrer"
                       href={`https://basescan.org/address/${status.address}`}>View contract</a>
                    <a style={styles.link} target="_blank" rel="noreferrer"
                       href={`https://basescan.org/tx/${status.hash}`}>View tx</a>
                    <a style={styles.link} target="_blank" rel="noreferrer"
                       href={`https://opensea.io/assets/base/${status.address}/1`}>OpenSea</a>
                  </div>
                </div>
              )}

              {status.kind === "already-deployed" && (
                <div style={styles.alertInfo}>
                  <div style={{ fontWeight: 700, marginBottom: 6 }}>Already deployed.</div>
                  <div style={styles.mono}>{status.address}</div>
                  <div style={{ marginTop: 10, display: "flex", gap: 12, flexWrap: "wrap" }}>
                    <a style={styles.link} target="_blank" rel="noreferrer"
                       href={`https://basescan.org/address/${status.address}`}>View contract</a>
                    <a style={styles.link} target="_blank" rel="noreferrer"
                       href={`https://opensea.io/assets/base/${status.address}/1`}>OpenSea</a>
                  </div>
                </div>
              )}

              {status.kind === "error" && (
                <div style={styles.alertBad}>{status.message}</div>
              )}
            </>
          )}
        </section>

        <footer style={styles.footer}>
          <div>Vaultfire Genesis · 1 of 1 · Solo · MIT · No token</div>
          <div style={styles.muted}>
            Source: <a style={styles.link} href="/nft/vaultfire-genesis.json" target="_blank" rel="noreferrer">metadata</a>
            {" · "}
            <a style={styles.link} href="/Vaultfire_Public_Reference.pdf" target="_blank" rel="noreferrer">reference PDF</a>
          </div>
        </footer>
      </div>
    </div>
  );
}

const styles: Record<string, React.CSSProperties> = {
  page: {
    minHeight: "100vh",
    background: "#0a0a0a",
    color: "#e8e8e8",
    fontFamily: "Inter, ui-sans-serif, system-ui, -apple-system, sans-serif",
    padding: "32px 16px",
    display: "flex",
    justifyContent: "center",
  },
  card: {
    width: "100%",
    maxWidth: 640,
    background: "#111",
    border: "1px solid #222",
    borderRadius: 16,
    padding: "28px 24px",
    boxShadow: "0 20px 60px rgba(0,0,0,0.4)",
  },
  header: { marginBottom: 18 },
  kicker: { color: "#01696F", fontSize: 12, letterSpacing: "0.2em", fontWeight: 700 },
  title: { fontSize: 30, margin: "6px 0 10px", fontWeight: 700 },
  lead: { color: "#aaa", lineHeight: 1.55, fontSize: 15 },
  previewWrap: {
    margin: "16px 0 22px",
    borderRadius: 12,
    overflow: "hidden",
    border: "1px solid #222",
    background: "#000",
  },
  preview: { width: "100%", display: "block" },
  grid: {
    display: "grid",
    gridTemplateColumns: "140px 1fr",
    rowGap: 8,
    columnGap: 12,
    margin: "0 0 22px",
    fontSize: 14,
  },
  dt: { color: "#888" },
  dd: { color: "#e8e8e8", margin: 0, wordBreak: "break-all" },
  section: { display: "flex", flexDirection: "column", gap: 12 },
  statusRow: {
    background: "#0d0d0d",
    border: "1px solid #1f1f1f",
    borderRadius: 10,
    padding: 12,
  },
  btnPrimary: {
    background: "#01696F",
    color: "#fff",
    border: "none",
    borderRadius: 10,
    padding: "14px 18px",
    fontSize: 15,
    fontWeight: 600,
    cursor: "pointer",
  },
  btnDisabled: {
    background: "#1a1a1a",
    color: "#888",
    border: "1px solid #222",
    borderRadius: 10,
    padding: "14px 18px",
    fontSize: 15,
    fontWeight: 600,
    cursor: "not-allowed",
  },
  btnSecondary: {
    background: "transparent",
    color: "#aaa",
    border: "1px solid #2a2a2a",
    borderRadius: 10,
    padding: "12px 18px",
    fontSize: 14,
    fontWeight: 500,
    cursor: "pointer",
  },
  alertGood: {
    background: "rgba(67,122,34,0.12)",
    border: "1px solid rgba(67,122,34,0.4)",
    color: "#cfe7be",
    padding: 12,
    borderRadius: 10,
    fontSize: 14,
  },
  alertInfo: {
    background: "rgba(1,105,111,0.12)",
    border: "1px solid rgba(1,105,111,0.4)",
    color: "#bfe6e8",
    padding: 12,
    borderRadius: 10,
    fontSize: 14,
  },
  alertBad: {
    background: "rgba(161,44,123,0.12)",
    border: "1px solid rgba(161,44,123,0.4)",
    color: "#f1c4dd",
    padding: 12,
    borderRadius: 10,
    fontSize: 14,
  },
  link: { color: "#4F98A3", textDecoration: "underline", wordBreak: "break-all" },
  code: {
    background: "#0a0a0a",
    border: "1px solid #1f1f1f",
    padding: "2px 6px",
    borderRadius: 6,
    fontFamily: "ui-monospace, Menlo, Consolas, monospace",
    fontSize: 13,
  },
  mono: { fontFamily: "ui-monospace, Menlo, Consolas, monospace", fontSize: 13, wordBreak: "break-all" },
  ens: { color: "#4F98A3", marginLeft: 8 },
  muted: { color: "#888", fontSize: 12 },
  footer: {
    marginTop: 22,
    paddingTop: 16,
    borderTop: "1px solid #1f1f1f",
    fontSize: 12,
    color: "#aaa",
    display: "flex",
    flexDirection: "column",
    gap: 6,
  },
};
