"use client";

import { createContext, useContext, useEffect, useMemo, useState, ReactNode } from "react";
import type { VaultReceipt, VaultState } from "@/lib/metaGame";
import { addKey, addReceipt, defaultVaultState, loadVaultState, saveVaultState, setFlag } from "@/lib/metaGame";
import {
  loadClaimedTxids,
  loadUsdStoreCredit,
  saveClaimedTxids,
  saveUsdStoreCredit,
} from "@/lib/storeCreditStorage";

interface WalletContextType {
  isConnected: boolean;
  address: string | null;
  chainId: number | null;
  connect: () => Promise<void>;
  disconnect: () => void;
  balance: string;
  luxCredits: number;
  usdStoreCredit: number;
  spendLuxCredits: (amount: number) => boolean;
  earnLuxCredits: (amount: number) => void;
  spendUsdStoreCredit: (amount: number) => boolean;
  verifyBtcDeposit: (txid: string) => Promise<{ ok: boolean; error?: string; creditedUsd?: number }>;
  vault: VaultState;
  collectKey: (key: string) => boolean;
  addVaultReceipt: (receipt: VaultReceipt) => void;
  setVaultFlag: (flag: string, value: boolean) => void;
}

const WalletContext = createContext<WalletContextType | undefined>(undefined);

export const useWallet = () => {
  const context = useContext(WalletContext);
  if (!context) {
    throw new Error("useWallet must be used within WalletProvider");
  }
  return context;
};

interface WalletProviderProps {
  children: ReactNode;
}

export const WalletProvider = ({ children }: WalletProviderProps) => {
  const [isConnected, setIsConnected] = useState(false);
  const [address, setAddress] = useState<string | null>(null);
  const [chainId, setChainId] = useState<number | null>(null);
  const [balance, setBalance] = useState("0.0");
  const [luxCredits, setLuxCredits] = useState(0);
  const [usdStoreCredit, setUsdStoreCredit] = useState(0);
  const [usdHydrated, setUsdHydrated] = useState(false);
  const [vault, setVault] = useState<VaultState>(() => defaultVaultState());

  const mockAddress = "0x71C7...e4a2";
  const mockChainId = 1;
  const mockBalance = "2.45";
  const startingLuxCredits = 5000;

  const connect = async () => {
    // Simulate wallet connection delay
    await new Promise((resolve) => setTimeout(resolve, 800));
    setIsConnected(true);
    setAddress(mockAddress);
    setChainId(mockChainId);
    setBalance(mockBalance);
    setLuxCredits(startingLuxCredits);
  };

  const disconnect = () => {
    setIsConnected(false);
    setAddress(null);
    setChainId(null);
    setBalance("0.0");
    setLuxCredits(0);
  };

  useEffect(() => {
    setVault(loadVaultState());
    setUsdStoreCredit(loadUsdStoreCredit());
    setUsdHydrated(true);
  }, []);

  useEffect(() => {
    saveVaultState(vault);
  }, [vault]);

  useEffect(() => {
    if (!usdHydrated) return;
    saveUsdStoreCredit(usdStoreCredit);
  }, [usdStoreCredit, usdHydrated]);

  const spendLuxCredits = (amount: number) => {
    const safeAmount = Number.isFinite(amount) ? Math.max(0, Math.floor(amount)) : 0;
    if (safeAmount <= 0) return true;
    if (luxCredits < safeAmount) return false;
    setLuxCredits((c) => c - safeAmount);
    return true;
  };

  const earnLuxCredits = (amount: number) => {
    const safeAmount = Number.isFinite(amount) ? Math.max(0, Math.floor(amount)) : 0;
    if (safeAmount <= 0) return;
    setLuxCredits((c) => c + safeAmount);
  };

  const spendUsdStoreCredit = (amount: number) => {
    const safe = Number.isFinite(amount) ? Math.max(0, Math.round(amount * 100) / 100) : 0;
    if (safe <= 0) return true;
    if (usdStoreCredit + 1e-9 < safe) return false;
    setUsdStoreCredit((u) => Math.round((u - safe) * 100) / 100);
    return true;
  };

  const verifyBtcDeposit = async (txid: string) => {
    const normalized = String(txid || "").trim();
    if (!/^[a-fA-F0-9]{64}$/.test(normalized)) {
      return { ok: false, error: "Enter a valid 64-character transaction id" };
    }
    const claimed = loadClaimedTxids();
    if (claimed.includes(normalized)) {
      return { ok: false, error: "This transaction was already used to add credit" };
    }
    try {
      const res = await fetch("/api/btc/verify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ txid: normalized }),
      });
      const data = (await res.json()) as {
        ok?: boolean;
        error?: string;
        creditedUsd?: number;
      };
      if (!data.ok || typeof data.creditedUsd !== "number") {
        return { ok: false, error: data.error || "Verification failed" };
      }
      claimed.push(normalized);
      saveClaimedTxids(claimed);
      const add = Math.round(data.creditedUsd * 100) / 100;
      setUsdStoreCredit((u) => Math.round((u + add) * 100) / 100);
      return { ok: true, creditedUsd: add };
    } catch {
      return { ok: false, error: "Network error while verifying" };
    }
  };

  const collectKey = (key: string) => {
    const trimmed = String(key || "").trim();
    if (!trimmed) return false;
    if (vault.keys.includes(trimmed)) return false;
    setVault((v) => addKey(v, trimmed));
    return true;
  };

  const addVaultReceipt = (receipt: VaultReceipt) => {
    setVault((v) => addReceipt(v, receipt));
  };

  const setVaultFlag = (flag: string, value: boolean) => {
    const f = String(flag || "").trim();
    if (!f) return;
    setVault((v) => setFlag(v, f, Boolean(value)));
  };

  const value = useMemo(
    () => ({
      isConnected,
      address,
      chainId,
      connect,
      disconnect,
      balance,
      luxCredits,
      usdStoreCredit,
      spendLuxCredits,
      earnLuxCredits,
      spendUsdStoreCredit,
      verifyBtcDeposit,
      vault,
      collectKey,
      addVaultReceipt,
      setVaultFlag,
    }),
    [isConnected, address, chainId, balance, luxCredits, usdStoreCredit, vault],
  );

  return (
    <WalletContext.Provider
      value={value}
    >
      {children}
    </WalletContext.Provider>
  );
};