// app/hooks/use-farcaster-context.tsx
import { useEffect, useState } from "react";

// app/constants.ts
var LOCAL_STORAGE_KEYS = {
  FARCASTER_USER: "farcasterUser",
  XMTP_SIGNER: "xmtpSigner",
  SELECTED_PROTOCOL: "selectedProtocol",
  FARCASTER_FRAME_CONTEXT: "farcasterFrameContext",
  XMTP_FRAME_CONTEXT: "xmtpFrameContext"
};

// app/hooks/use-farcaster-context.tsx
function useFarcasterFrameContext({
  fallbackContext
}) {
  const [frameContext, setFrameContext] = useState(null);
  useEffect(() => {
    const storedData = localStorage.getItem(
      LOCAL_STORAGE_KEYS.FARCASTER_FRAME_CONTEXT
    );
    if (storedData) {
      setFrameContext(JSON.parse(storedData));
    }
  }, []);
  useEffect(() => {
    if (frameContext) {
      localStorage.setItem(
        LOCAL_STORAGE_KEYS.FARCASTER_FRAME_CONTEXT,
        JSON.stringify(frameContext)
      );
    }
  }, [frameContext]);
  function resetFrameContext() {
    localStorage.removeItem(LOCAL_STORAGE_KEYS.FARCASTER_FRAME_CONTEXT);
    setFrameContext(null);
  }
  return {
    frameContext: frameContext || fallbackContext,
    setFrameContext,
    resetFrameContext
  };
}

// app/hooks/use-farcaster-identity.tsx
import { useEffect as useEffect2, useState as useState2 } from "react";

// app/lib/crypto.ts
import * as ed from "@noble/ed25519";
function convertKeypairToHex({
  privateKeyBytes,
  publicKeyBytes
}) {
  return {
    publicKey: "0x" + Buffer.from(publicKeyBytes).toString("hex"),
    privateKey: "0x" + Buffer.from(privateKeyBytes).toString("hex")
  };
}
async function createKeypairEDDSA() {
  const privateKeyBytes = ed.utils.randomPrivateKey();
  const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
  return {
    privateKeyBytes,
    publicKeyBytes
  };
}

// app/hooks/use-farcaster-identity.tsx
import {
  signFrameAction
} from "@frames.js/render";
function useFarcasterIdentity() {
  const [isLoading, setLoading] = useState2(false);
  const [farcasterUser, setFarcasterSigner] = useState2(
    getSignerFromLocalStorage()
  );
  async function impersonateUser({ fid }) {
    const keypair = await createKeypairEDDSA();
    const { privateKey, publicKey } = convertKeypairToHex(keypair);
    const signer = {
      status: "impersonating",
      fid,
      // signature: "1",
      // is ignored for non pending
      // deadline: new Date().getTime(),
      privateKey,
      publicKey
    };
    localStorage.setItem(
      LOCAL_STORAGE_KEYS.FARCASTER_USER,
      JSON.stringify(signer)
    );
    setFarcasterSigner(signer);
  }
  function getSignerFromLocalStorage() {
    if (typeof window !== "undefined") {
      const storedData = localStorage.getItem(
        LOCAL_STORAGE_KEYS.FARCASTER_USER
      );
      if (storedData) {
        const signer = JSON.parse(storedData);
        if (signer.status === "pending_approval") {
          if (signer.deadline && signer.deadline < Math.floor(Date.now() / 1e3)) {
            localStorage.removeItem(LOCAL_STORAGE_KEYS.FARCASTER_USER);
            return null;
          }
        }
        return signer;
      }
      return null;
    }
    return null;
  }
  useEffect2(() => {
    const signer = getSignerFromLocalStorage();
    if (signer)
      setFarcasterSigner(signer);
  }, []);
  function logout() {
    localStorage.setItem(LOCAL_STORAGE_KEYS.FARCASTER_USER, "");
    setFarcasterSigner(null);
  }
  useEffect2(() => {
    if (farcasterUser && farcasterUser.status === "pending_approval") {
      let intervalId;
      const startPolling = () => {
        intervalId = setInterval(async () => {
          try {
            const fcSignerRequestResponse = await fetch(
              `https://api.warpcast.com/v2/signed-key-request?token=${farcasterUser.token}`,
              {
                method: "GET",
                headers: {
                  "Content-Type": "application/json"
                }
              }
            );
            const responseBody = await fcSignerRequestResponse.json();
            if (responseBody.result.signedKeyRequest.state !== "completed") {
              throw new Error("hasnt succeeded yet");
            }
            const user = {
              ...farcasterUser,
              ...responseBody.result,
              fid: responseBody.result.signedKeyRequest.userFid,
              status: "approved"
            };
            localStorage.setItem(
              LOCAL_STORAGE_KEYS.FARCASTER_USER,
              JSON.stringify(user)
            );
            setFarcasterSigner(user);
            clearInterval(intervalId);
          } catch (error) {
            console.info(error);
          }
        }, 2e3);
      };
      const stopPolling = () => {
        clearInterval(intervalId);
      };
      const handleVisibilityChange = () => {
        if (document.hidden) {
          stopPolling();
        } else {
          startPolling();
        }
      };
      document.addEventListener("visibilitychange", handleVisibilityChange);
      startPolling();
      return () => {
        document.removeEventListener(
          "visibilitychange",
          handleVisibilityChange
        );
        clearInterval(intervalId);
      };
    }
  }, [farcasterUser]);
  async function onSignerlessFramePress() {
    setLoading(true);
    await createAndStoreSigner();
    setLoading(false);
  }
  async function createAndStoreSigner() {
    try {
      const keypair = await createKeypairEDDSA();
      const keypairString = convertKeypairToHex(keypair);
      const authorizationResponse = await fetch(`/signer`, {
        method: "POST",
        body: JSON.stringify({
          publicKey: keypairString.publicKey
        })
      });
      const authorizationBody = await authorizationResponse.json();
      if (authorizationResponse.status === 200) {
        const { signature, requestFid, deadline } = authorizationBody;
        const {
          result: { signedKeyRequest }
        } = await (await fetch(`https://api.warpcast.com/v2/signed-key-requests`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            key: keypairString.publicKey,
            signature,
            requestFid,
            deadline
          })
        })).json();
        const signer = {
          ...authorizationBody,
          publicKey: keypairString.publicKey,
          deadline,
          token: signedKeyRequest.token,
          signerApprovalUrl: signedKeyRequest.deeplinkUrl,
          privateKey: keypairString.privateKey,
          status: "pending_approval"
        };
        localStorage.setItem(
          LOCAL_STORAGE_KEYS.FARCASTER_USER,
          JSON.stringify(signer)
        );
        setFarcasterSigner(signer);
      } else if (authorizationBody.code === 1) {
        window.alert(
          authorizationBody.message
        );
      }
    } catch (error) {
      console.error("frames.js: API Call failed", error);
    }
  }
  return {
    signer: farcasterUser,
    hasSigner: !!farcasterUser?.fid && !!farcasterUser.privateKey,
    signFrameAction,
    isLoading: null,
    isLoadingSigner: isLoading,
    impersonateUser,
    onSignerlessFramePress,
    logout
  };
}

// app/hooks/use-xmtp-identity.tsx
import { useConnectModal } from "@rainbow-me/rainbowkit";
import { FramesClient } from "@xmtp/frames-client";
import { Client } from "@xmtp/xmtp-js";
import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
import { zeroAddress } from "viem";
import { useAccount, useConfig } from "wagmi";
import { getAccount, signMessage } from "wagmi/actions";
function useXmtpIdentity() {
  const [isLoading, setLoading] = useState3(false);
  const [xmtpSigner, setXmtpSigner] = useState3(null);
  const [xmtpClient, setXmtpClient] = useState3(null);
  const config = useConfig();
  const connect = useConnectModal();
  const { address } = useAccount();
  const walletSigner = useMemo(
    () => address ? {
      getAddress() {
        return Promise.resolve(address);
      },
      signMessage(message) {
        return signMessage(config, {
          message: {
            raw: typeof message === "string" ? Buffer.from(message) : Buffer.from(message)
          }
        });
      }
    } : null,
    [address, config]
  );
  function getSignerFromLocalStorage() {
    if (typeof window !== "undefined") {
      const storedData = localStorage.getItem(LOCAL_STORAGE_KEYS.XMTP_SIGNER);
      if (storedData) {
        const signerRaw = JSON.parse(storedData);
        const signer = {
          walletAddress: signerRaw.walletAddress,
          keys: Buffer.from(signerRaw.keys, "hex")
        };
        return signer;
      }
      return null;
    }
    return null;
  }
  useEffect3(() => {
    const signer = getSignerFromLocalStorage();
    if (signer)
      setXmtpSigner(signer);
  }, []);
  useEffect3(() => {
    if (xmtpSigner) {
      Client.create(null, {
        privateKeyOverride: xmtpSigner.keys
      }).then((client) => setXmtpClient(client));
    }
  }, [xmtpSigner]);
  function logout() {
    localStorage.removeItem(LOCAL_STORAGE_KEYS.XMTP_SIGNER);
    setXmtpSigner(null);
  }
  async function onSignerlessFramePress() {
    setLoading(true);
    await createAndStoreSigner();
    setLoading(false);
  }
  async function createAndStoreSigner() {
    try {
      if (!xmtpSigner) {
        if (!walletSigner) {
          connect.openConnectModal?.();
          return;
        }
        Client.getKeys(walletSigner, {
          env: "dev",
          skipContactPublishing: true,
          persistConversations: false
        }).then((keys) => {
          const walletAddress = getAccount(config).address || zeroAddress;
          localStorage.setItem(
            LOCAL_STORAGE_KEYS.XMTP_SIGNER,
            JSON.stringify({
              walletAddress,
              keys: Buffer.from(keys).toString("hex")
            })
          );
          setXmtpSigner({
            keys,
            walletAddress
          });
        });
      }
    } catch (error) {
      console.error("frames.js: API Call failed", error);
    }
  }
  return {
    signer: xmtpSigner,
    hasSigner: !!xmtpSigner?.keys,
    async signFrameAction(actionContext) {
      if (!xmtpClient) {
        throw new Error("No xmtp client");
      }
      if (!address) {
        throw new Error("No address");
      }
      const framesClient = new FramesClient(xmtpClient);
      const payload = await framesClient.signFrameAction({
        frameUrl: actionContext.url,
        inputText: actionContext.inputText,
        state: actionContext.state,
        buttonIndex: actionContext.buttonIndex,
        conversationTopic: actionContext.frameContext.conversationTopic,
        participantAccountAddresses: actionContext.frameContext.participantAccountAddresses,
        ...actionContext.frameContext.groupId ? { groupId: actionContext.frameContext.groupId } : {},
        ...actionContext.frameContext.groupSecret ? { groupSecret: actionContext.frameContext.groupSecret } : {}
      });
      const searchParams = new URLSearchParams({
        postType: actionContext.transactionId ? "post" : actionContext.frameButton.action,
        postUrl: actionContext.frameButton.target ?? ""
      });
      return {
        body: payload,
        searchParams
      };
    },
    isLoading: null,
    isLoadingSigner: isLoading,
    onSignerlessFramePress,
    logout
  };
}

// app/hooks/use-xmtp-context.tsx
import { useEffect as useEffect4, useState as useState4 } from "react";
function useXmtpFrameContext({
  fallbackContext
}) {
  const [frameContext, setFrameContext] = useState4(
    null
  );
  useEffect4(() => {
    const storedData = localStorage.getItem(
      LOCAL_STORAGE_KEYS.XMTP_FRAME_CONTEXT
    );
    if (storedData) {
      setFrameContext(JSON.parse(storedData));
    }
  }, []);
  useEffect4(() => {
    if (frameContext) {
      localStorage.setItem(
        LOCAL_STORAGE_KEYS.XMTP_FRAME_CONTEXT,
        JSON.stringify(frameContext)
      );
    }
  }, [frameContext]);
  function resetFrameContext() {
    localStorage.removeItem(LOCAL_STORAGE_KEYS.XMTP_FRAME_CONTEXT);
    setFrameContext(null);
  }
  return {
    frameContext: frameContext || fallbackContext,
    setFrameContext,
    resetFrameContext
  };
}
export {
  useFarcasterFrameContext,
  useFarcasterIdentity,
  useXmtpFrameContext,
  useXmtpIdentity
};
