import React, { createContext, useContext, useState, useEffect, useRef } from 'react';
import { useToast } from '@/components/ui/use-toast';
import { User } from '@/types';
import { AuthService, AuthResult } from '@/lib/identity/services/AuthService';
import { OpchanMessage } from '@/types';
import { useAppKitAccount, useDisconnect } from '@reown/appkit/react';

export type VerificationStatus = 'unverified' | 'verified-none' | 'verified-owner' | 'verifying';

interface AuthContextType {
  currentUser: User | null;
  isAuthenticated: boolean;
  isAuthenticating: boolean;
  verificationStatus: VerificationStatus;
  verifyOrdinal: () => Promise<boolean>;
  delegateKey: () => Promise<boolean>;
  isDelegationValid: () => boolean;
  delegationTimeRemaining: () => number;
  isWalletAvailable: () => boolean;
  messageSigning: {
    signMessage: (message: OpchanMessage) => Promise<OpchanMessage | null>;
    verifyMessage: (message: OpchanMessage) => boolean;
  };
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export { AuthContext };

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [currentUser, setCurrentUser] = useState<User | null>(null);
  const [isAuthenticating, setIsAuthenticating] = useState(false);
  const [verificationStatus, setVerificationStatus] = useState<VerificationStatus>('unverified');
  const { toast } = useToast();
  
  // Use AppKit hooks for multi-chain support
  const bitcoinAccount = useAppKitAccount({ namespace: "bip122" });
  const ethereumAccount = useAppKitAccount({ namespace: "eip155" });
  
  // Determine which account is connected
  const isBitcoinConnected = bitcoinAccount.isConnected;
  const isEthereumConnected = ethereumAccount.isConnected;
  const isConnected = isBitcoinConnected || isEthereumConnected;
  
  // Get the active account info
  const activeAccount = isBitcoinConnected ? bitcoinAccount : ethereumAccount;
  const address = activeAccount.address;
  
  // Create ref for AuthService so it persists between renders
  const authServiceRef = useRef(new AuthService());
  
  // Sync with AppKit wallet state
  useEffect(() => {
    if (isConnected && address) {
      // Check if we have a stored user for this address
      const storedUser = authServiceRef.current.loadStoredUser();
      
      if (storedUser && storedUser.address === address) {
        // Use stored user data
        setCurrentUser(storedUser);
        if ('ordinalOwnership' in storedUser) {
          setVerificationStatus(storedUser.ordinalOwnership ? 'verified-owner' : 'verified-none');
        } else {
          setVerificationStatus('unverified');
        }
      } else {
        // Create new user from AppKit wallet
        const newUser: User = {
          address,
          walletType: isBitcoinConnected ? 'bitcoin' : 'ethereum',
          ordinalOwnership: false,
          delegationExpiry: null,
          verificationStatus: 'unverified',
        };
        setCurrentUser(newUser);
        setVerificationStatus('unverified');
        authServiceRef.current.saveUser(newUser);
        
        const chainName = isBitcoinConnected ? 'Bitcoin' : 'Ethereum';
        toast({
          title: "Wallet Connected",
          description: `Connected to ${chainName} with address ${address.slice(0, 6)}...${address.slice(-4)}`,
        });
        
        toast({
          title: "Action Required",
          description: "Please verify your Ordinal ownership and delegate a signing key for better UX.",
        });
      }
    } else {
      // Wallet disconnected
      setCurrentUser(null);
      setVerificationStatus('unverified');
    }
  }, [isConnected, address, isBitcoinConnected, toast]);

  const verifyOrdinal = async (): Promise<boolean> => {
    if (!currentUser || !currentUser.address) {
      toast({
        title: "Not Connected",
        description: "Please connect your wallet first.",
        variant: "destructive",
      });
      return false;
    }
    
    setIsAuthenticating(true);
    setVerificationStatus('verifying');
    
    try {
      toast({ 
        title: "Verifying Ordinal", 
        description: "Checking your wallet for Ordinal Operators..." 
      });
      
      const result: AuthResult = await authServiceRef.current.verifyOrdinal(currentUser);
      
      if (!result.success) {
        throw new Error(result.error);
      }
      
      const updatedUser = result.user!;
      setCurrentUser(updatedUser);
      authServiceRef.current.saveUser(updatedUser);
      
      // Update verification status
      setVerificationStatus(updatedUser.ordinalOwnership ? 'verified-owner' : 'verified-none');
      
      if (updatedUser.ordinalOwnership) {
        toast({
          title: "Ordinal Verified",
          description: "You now have full access. We recommend delegating a key for better UX.",
        });
      } else {
        toast({
          title: "Read-Only Access",
          description: "No Ordinal Operators found. You have read-only access.",
          variant: "default",
        });
      }
      
      return Boolean(updatedUser.ordinalOwnership);
    } catch (error) {
      console.error("Error verifying Ordinal:", error);
      setVerificationStatus('unverified');
      
      let errorMessage = "Failed to verify Ordinal ownership. Please try again.";
      if (error instanceof Error) {
        errorMessage = error.message;
      }
      
      toast({
        title: "Verification Error",
        description: errorMessage,
        variant: "destructive",
      });
      
      return false;
    } finally {
      setIsAuthenticating(false);
    }
  };

  const delegateKey = async (): Promise<boolean> => {
    if (!currentUser || !currentUser.address) {
      toast({
        title: "Not Connected",
        description: "Please connect your wallet first.",
        variant: "destructive",
      });
      return false;
    }
    
    setIsAuthenticating(true);
    
    try {
      toast({
        title: "Starting Key Delegation",
        description: "This will let you post, comment, and vote without approving each action for 24 hours.",
      });
      
      const result: AuthResult = await authServiceRef.current.delegateKey(currentUser);
      
      if (!result.success) {
        throw new Error(result.error);
      }
      
      const updatedUser = result.user!;
      setCurrentUser(updatedUser);
      authServiceRef.current.saveUser(updatedUser);
      
      // Format date for user-friendly display
      const expiryDate = new Date(updatedUser.delegationExpiry!);
      const formattedExpiry = expiryDate.toLocaleString();
      
      toast({
        title: "Key Delegation Successful",
        description: `You can now interact with the forum without additional wallet approvals until ${formattedExpiry}.`,
      });
      
      return true;
    } catch (error) {
      console.error("Error delegating key:", error);
      
      let errorMessage = "Failed to delegate key. Please try again.";
      
      if (error instanceof Error) {
        // Provide specific guidance based on error type
        if (error.message.includes("rejected") || error.message.includes("declined") || error.message.includes("denied")) {
          errorMessage = "You declined the signature request. Key delegation is optional but improves your experience.";
        } else if (error.message.includes("timeout")) {
          errorMessage = "Wallet request timed out. Please try again and approve the signature promptly.";
        } else if (error.message.includes("Failed to connect wallet")) {
          errorMessage = "Unable to connect to wallet. Please ensure it's installed and unlocked, then try again.";
        } else if (error.message.includes("Wallet is not connected")) {
          errorMessage = "Wallet connection was lost. Please reconnect your wallet and try again.";
        } else {
          errorMessage = error.message;
        }
      }
      
      toast({
        title: "Delegation Failed",
        description: errorMessage,
        variant: "destructive",
      });
      
      return false;
    } finally {
      setIsAuthenticating(false);
    }
  };
  
  const isDelegationValid = (): boolean => {
    return authServiceRef.current.isDelegationValid();
  };
  
  const delegationTimeRemaining = (): number => {
    return authServiceRef.current.getDelegationTimeRemaining();
  };

  const isWalletAvailable = (): boolean => {
    return isConnected && !!address;
  };

  return (
    <AuthContext.Provider
      value={{
        currentUser,
        isAuthenticated: !!currentUser?.ordinalOwnership,
        isAuthenticating,
        verificationStatus,
        verifyOrdinal,
        delegateKey,
        isDelegationValid,
        delegationTimeRemaining,
        isWalletAvailable,
        messageSigning: {
          signMessage: (message: OpchanMessage) => authServiceRef.current.signMessage(message),
          verifyMessage: (message: OpchanMessage) => authServiceRef.current.verifyMessage(message),
        },
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}


