"use client";

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

// The owner-only deploy step is locked to ghostkey.base.eth.
// Public mint after the contract address is known is open to anyone.
const ALLOWED_DEPLOYER: Address = "0xfA15Ee28939B222B0448261A22156070f0A7813C";
const ALLOWED_VNS = "ghostkey.base.eth";

const BASE_URI = "https://theloopbreaker.com/nft/founders/";
const PRICE_ETH = "0.1";
const MAX_SUPPLY = 5;

const IMG = "/nft/vaultfire-founders.png";

// CREATE2 deterministic deploy via Arachnid factory.
// PREDICTED is the address the contract WILL live at — same on every redeploy attempt.
const FACTORY: Address = create2.factory as Address;
const SALT: `0x${string}` = create2.founders.salt as `0x${string}`;
const PREDICTED: Address = create2.founders.predicted as Address;

const basePublic = createPublicClient({ chain: base, transport: http() });
const ethPublic = createPublicClient({ chain: mainnet, transport: http() });

type Phase =
  | { kind: "idle" }
  | { kind: "deploying"; hash?: Hash }
  | { kind: "deployed"; address: Address }
  | { kind: "minting"; hash?: Hash }
  | { kind: "minted"; hash: Hash; tokenId?: number }
  | { kind: "error"; message: string };

export default function MintFoundersPage() {
  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 [contractDeployed, setContractDeployed] = useState<boolean>(false);
  const [totalSupply, setTotalSupply] = useState<number | null>(null);
  const [phase, setPhase] = useState<Phase>({ kind: "idle" });

  // Contract address is deterministic via CREATE2 — known before deploy.
  const contractAddr: Address = PREDICTED;

  const isDeployer = useMemo(
    () => !!account && account.toLowerCase() === ALLOWED_DEPLOYER.toLowerCase(),
    [account]
  );
  const onBase = chainId === base.id;

  // Probe predicted address — if code already exists, public mint is open.
  useEffect(() => {
    (async () => {
      try {
        const code = await basePublic.getBytecode({ address: PREDICTED });
        setContractDeployed(!!code && code !== "0x");
      } catch {
        setContractDeployed(false);
      }
    })();
  }, [phase]);

  // Wallet wiring
  useEffect(() => {
    if (typeof window === "undefined") return;
    const eth = (window as any).ethereum;
    if (!eth) return;
    (async () => {
      try {
        const accs: string[] = await eth.request({ method: "eth_accounts" });
        if (accs?.[0]) setAccount(accs[0] as Address);
        const cid: string = await eth.request({ method: "eth_chainId" });
        setChainId(parseInt(cid, 16));
      } catch {}
    })();
    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 {
        setEnsName((await ethPublic.getEnsName({ address: account })) ?? null);
      } catch {
        setEnsName(null);
      }
      try {
        const b = await basePublic.getBalance({ address: account });
        setBalance(formatEther(b));
      } catch {}
    })();
  }, [account]);

  // Refresh totalSupply once contract is known to be deployed, and after each tx.
  useEffect(() => {
    if (!contractDeployed) {
      setTotalSupply(null);
      return;
    }
    (async () => {
      try {
        const ts = (await basePublic.readContract({
          address: contractAddr,
          abi: artifact.abi as any,
          functionName: "totalSupply",
        })) as bigint;
        setTotalSupply(Number(ts));
      } catch {
        setTotalSupply(null);
      }
    })();
  }, [contractDeployed, phase]);

  async function connect() {
    const eth = (window as any).ethereum;
    if (!eth) {
      setPhase({ 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) {
      setPhase({ 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" }] });
    } catch (e: any) {
      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 {
        setPhase({ kind: "error", message: e?.message ?? "Failed to switch network" });
      }
    }
  }

  async function deploy() {
    if (!account || !isDeployer) return;
    if (!onBase) { await switchToBase(); return; }
    setPhase({ kind: "deploying" });
    try {
      // Short-circuit: if the predicted address already has code, deploy is done.
      const existingCode = await basePublic.getBytecode({ address: PREDICTED });
      if (existingCode && existingCode !== "0x") {
        setContractDeployed(true);
        setPhase({ kind: "deployed", address: PREDICTED });
        return;
      }

      // Build CREATE2 calldata: salt(32) ++ initcode
      // initcode = bytecode ++ abi.encode(constructor args)
      const ctorArgs = encodeAbiParameters(
        [
          { type: "address", name: "owner_" },
          { type: "string", name: "baseURI_" },
        ],
        [ALLOWED_DEPLOYER, BASE_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",
        }],
      });
      setPhase({ kind: "deploying", hash });

      const receipt = await basePublic.waitForTransactionReceipt({ hash });
      if (receipt.status !== "success") {
        throw new Error(`Tx ${hash} reverted on-chain.`);
      }
      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.`);
      }
      setContractDeployed(true);
      setPhase({ kind: "deployed", address: PREDICTED });
    } catch (e: any) {
      setPhase({ kind: "error", message: e?.shortMessage ?? e?.message ?? "Deploy failed" });
    }
  }

  async function mint() {
    if (!account || !contractDeployed) return;
    if (!onBase) { await switchToBase(); return; }
    setPhase({ kind: "minting" });
    try {
      const eth = (window as any).ethereum;
      const wallet = createWalletClient({ chain: base, transport: custom(eth), account });
      const data = encodeFunctionData({ abi: artifact.abi as any, functionName: "mint", args: [] });
      const hash = await wallet.sendTransaction({
        to: contractAddr,
        data,
        value: parseEther(PRICE_ETH),
      });
      setPhase({ kind: "minting", hash });
      await basePublic.waitForTransactionReceipt({ hash });
      // Re-read totalSupply to know which token was just minted (the new last one).
      let tokenId: number | undefined = undefined;
      try {
        const ts = (await basePublic.readContract({
          address: contractAddr, abi: artifact.abi as any, functionName: "totalSupply",
        })) as bigint;
        tokenId = Number(ts);
      } catch {}
      setPhase({ kind: "minted", hash, tokenId });
    } catch (e: any) {
      setPhase({ kind: "error", message: e?.shortMessage ?? e?.message ?? "Mint failed" });
    }
  }

  const remaining = totalSupply == null ? null : Math.max(0, MAX_SUPPLY - totalSupply);
  const soldOut = remaining === 0;

  return (
    <div style={S.page}>
      <div style={S.card}>
        <header style={S.header}>
          <div style={S.kicker}>VAULTFIRE</div>
          <h1 style={S.title}>Founders Edition</h1>
          <p style={S.lead}>
            Five Founders NFTs commemorating the first public mile of Vaultfire — KYA Trust Infrastructure for AI Agents.
            Companion to the Genesis 1/1. Mint funds the protocol; 5% royalties on every secondary sale go back to{" "}
            <code style={S.code}>{ALLOWED_VNS}</code>.
          </p>
          <div style={S.anonBadge}>
            No KYC. No signup. No email. Mint anonymously from any Base wallet.
          </div>
        </header>

        <div style={S.previewWrap}>
          <img src={IMG} alt="Vaultfire Founders Edition" style={S.preview} />
        </div>

        <dl style={S.grid}>
          <dt style={S.dt}>Standard</dt><dd style={S.dd}>ERC-721 + ERC-2981</dd>
          <dt style={S.dt}>Chain</dt><dd style={S.dd}>Base · 8453</dd>
          <dt style={S.dt}>Supply</dt>
          <dd style={S.dd}>
            {totalSupply == null ? `${MAX_SUPPLY} max` :
              soldOut ? <strong>Sold out</strong> :
              <>{totalSupply} of {MAX_SUPPLY} minted · <strong>{remaining} left</strong></>}
          </dd>
          <dt style={S.dt}>Price</dt><dd style={S.dd}>{PRICE_ETH} ETH per mint</dd>
          <dt style={S.dt}>Royalties</dt><dd style={S.dd}>5% to {ALLOWED_VNS}</dd>
          <dt style={S.dt}>Contract</dt>
          <dd style={S.dd}>
            <a style={S.link} target="_blank" rel="noreferrer" href={`https://basescan.org/address/${contractAddr}`}>
              {contractAddr}
            </a>
            {!contractDeployed && <span style={S.muted}> · awaiting first deploy</span>}
          </dd>
        </dl>

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

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

              {/* Deploy step — only deployer wallet, only when not deployed yet */}
              {onBase && !contractDeployed && isDeployer && (
                <button
                  onClick={() => deploy()}
                  disabled={phase.kind === "deploying"}
                  style={phase.kind === "deploying" ? S.btnDisabled : S.btnPrimary}
                >
                  {phase.kind === "deploying" ? "Deploying\u2026" : "Deploy contract (one-time)"}
                </button>
              )}

              {onBase && !contractDeployed && !isDeployer && (
                <div style={S.alertInfo}>
                  Mint opens after {ALLOWED_VNS} deploys the contract. Check back in a minute.
                </div>
              )}

              {/* Public mint */}
              {onBase && contractDeployed && !soldOut && phase.kind !== "minted" && (
                <button
                  onClick={mint}
                  disabled={phase.kind === "minting" || remaining === 0}
                  style={phase.kind === "minting" ? S.btnDisabled : S.btnPrimary}
                >
                  {phase.kind === "minting" ? "Minting…" : `Mint for ${PRICE_ETH} ETH`}
                </button>
              )}

              {soldOut && (
                <div style={S.alertGood}>
                  Sold out. Find them on{" "}
                  <a style={S.link} target="_blank" rel="noreferrer"
                     href={`https://opensea.io/assets/base/${contractAddr}/1`}>OpenSea</a>.
                </div>
              )}

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

              {phase.kind === "deployed" && (
                <div style={S.alertGood}>
                  Contract live at {PREDICTED}. Public mint is now open.
                </div>
              )}

              {phase.kind === "minting" && phase.hash && (
                <div style={S.alertInfo}>
                  Mint tx:{" "}
                  <a style={S.link} target="_blank" rel="noreferrer"
                     href={`https://basescan.org/tx/${phase.hash}`}>{phase.hash.slice(0, 18)}…</a>
                </div>
              )}

              {phase.kind === "minted" && (
                <div style={S.alertGood}>
                  <div style={{ fontWeight: 700, marginBottom: 6 }}>
                    Minted Founders #{phase.tokenId ?? "?"}.
                  </div>
                  <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
                    <a style={S.link} target="_blank" rel="noreferrer"
                       href={`https://basescan.org/tx/${phase.hash}`}>View tx</a>
                    {phase.tokenId && contractAddr && (
                      <a style={S.link} target="_blank" rel="noreferrer"
                         href={`https://opensea.io/assets/base/${contractAddr}/${phase.tokenId}`}>OpenSea</a>
                    )}
                  </div>
                </div>
              )}

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

        <footer style={S.footer}>
          <div>Vaultfire Founders Edition · 5 max · Solo · MIT · No token</div>
          <div style={S.muted}>
            <a style={S.link} href="/mint-genesis">Genesis 1/1</a>{" · "}
            <a style={S.link} href="/Vaultfire_Public_Reference.pdf" target="_blank" rel="noreferrer">reference PDF</a>
          </div>
        </footer>
      </div>
    </div>
  );
}

const S: 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,
  },
  anonBadge: {
    marginTop: 14,
    padding: "8px 12px",
    background: "rgba(67,122,34,0.10)",
    border: "1px solid rgba(67,122,34,0.35)",
    borderRadius: 8,
    color: "#cfe7be",
    fontSize: 13,
    lineHeight: 1.4,
    fontWeight: 500,
  },
  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,
  },
};
