import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';
import { Cell, Post, Comment, OpchanMessage, User, EVerificationStatus } from '@/types/forum';
import { useToast } from '@/components/ui/use-toast';
import { useAuth } from '@/contexts/useAuth';
import { 
  createPost, 
  createComment, 
  vote, 
  createCell, 
  moderatePost, 
  moderateComment, 
  moderateUser 
} from '@/lib/forum/actions';
import { 
  setupPeriodicQueries, 
  monitorNetworkHealth, 
  initializeNetwork 
} from '@/lib/waku/network';
import messageManager from '@/lib/waku';
import { getDataFromCache } from '@/lib/forum/transformers';
import { RelevanceCalculator } from '@/lib/forum/relevance';
import { UserVerificationStatus } from '@/types/forum';
import { CryptoService, AuthService } from '@/lib/identity/services';
import { getEnsName } from '@wagmi/core';
import { config } from '@/lib/identity/wallets/appkit';

interface ForumContextType {
  cells: Cell[];
  posts: Post[];
  comments: Comment[];
  // User verification status for display
  userVerificationStatus: UserVerificationStatus;
  // Granular loading states
  isInitialLoading: boolean;
  isPostingCell: boolean;
  isPostingPost: boolean;
  isPostingComment: boolean;
  isVoting: boolean;
  isRefreshing: boolean;
  // Network status
  isNetworkConnected: boolean;
  error: string | null;
  getCellById: (id: string) => Cell | undefined;
  getPostsByCell: (cellId: string) => Post[];
  getCommentsByPost: (postId: string) => Comment[];
  createPost: (cellId: string, title: string, content: string) => Promise<Post | null>;
  createComment: (postId: string, content: string) => Promise<Comment | null>;
  votePost: (postId: string, isUpvote: boolean) => Promise<boolean>;
  voteComment: (commentId: string, isUpvote: boolean) => Promise<boolean>;
  createCell: (name: string, description: string, icon?: string) => Promise<Cell | null>;
  refreshData: () => Promise<void>;
  moderatePost: (
    cellId: string,
    postId: string,
    reason: string | undefined,
    cellOwner: string
  ) => Promise<boolean>;
  moderateComment: (
    cellId: string,
    commentId: string,
    reason: string | undefined,
    cellOwner: string
  ) => Promise<boolean>;
  moderateUser: (
    cellId: string,
    userAddress: string,
    reason: string | undefined,
    cellOwner: string
  ) => Promise<boolean>;
}

const ForumContext = createContext<ForumContextType | undefined>(undefined);

export { ForumContext };

export function ForumProvider({ children }: { children: React.ReactNode }) {
  const [cells, setCells] = useState<Cell[]>([]);
  const [posts, setPosts] = useState<Post[]>([]);
  const [comments, setComments] = useState<Comment[]>([]);
  const [isInitialLoading, setIsInitialLoading] = useState(true);
  const [isPostingCell, setIsPostingCell] = useState(false);
  const [isPostingPost, setIsPostingPost] = useState(false);
  const [isPostingComment, setIsPostingComment] = useState(false);
  const [isVoting, setIsVoting] = useState(false);
  const [isRefreshing, setIsRefreshing] = useState(false);
  const [isNetworkConnected, setIsNetworkConnected] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [userVerificationStatus, setUserVerificationStatus] = useState<UserVerificationStatus>({});
  
  const { toast } = useToast();
  const { currentUser, isAuthenticated } = useAuth();
  
  const cryptoService = useMemo(() => new CryptoService(), []);
  const authService = useMemo(() => new AuthService(cryptoService), [cryptoService]);
  
  // Transform message cache data to the expected types
  const updateStateFromCache = useCallback(() => {
    // Use the verifyMessage function from cryptoService if available
    const verifyFn = isAuthenticated ? 
      (message: OpchanMessage) => cryptoService.verifyMessage(message) : 
      undefined;
    
    // Build user verification status for relevance calculation
    const relevanceCalculator = new RelevanceCalculator();
    const allUsers: User[] = [];
    
    // Collect all unique users from posts, comments, and votes
    const userAddresses = new Set<string>();
    
    // Add users from posts
    Object.values(messageManager.messageCache.posts).forEach(post => {
      userAddresses.add(post.author);
    });
    
    // Add users from comments
    Object.values(messageManager.messageCache.comments).forEach(comment => {
      userAddresses.add(comment.author);
    });
    
    // Add users from votes
    Object.values(messageManager.messageCache.votes).forEach(vote => {
      userAddresses.add(vote.author);
    });
    
    // Create user objects for verification status
    Array.from(userAddresses).forEach(address => {
      // Check if this address matches the current user's address
      if (currentUser && currentUser.address === address) {
        // Use the current user's actual verification status
        allUsers.push({
          address,
          walletType: currentUser.walletType,
          verificationStatus: currentUser.verificationStatus,
          ensOwnership: currentUser.ensOwnership,
          ensName: currentUser.ensName,
          ensAvatar: currentUser.ensAvatar,
          ordinalOwnership: currentUser.ordinalOwnership,
          lastChecked: currentUser.lastChecked
        });
      } else {
        // Create generic user object for other addresses
        allUsers.push({
          address,
          walletType: address.startsWith('0x') ? 'ethereum' : 'bitcoin',
          verificationStatus: EVerificationStatus.UNVERIFIED
        });
      }
    });
    
    const initialStatus = relevanceCalculator.buildUserVerificationStatus(allUsers);
    
    // Transform data with relevance calculation (initial pass)
    const { cells, posts, comments } = getDataFromCache(verifyFn, initialStatus);
    
    setCells(cells);
    setPosts(posts);
    setComments(comments);
    setUserVerificationStatus(initialStatus);

    // Enrich: resolve ENS for ethereum addresses asynchronously and update
    (async () => {
      const targets = allUsers.filter(u => u.walletType === 'ethereum' && !u.ensOwnership);
      if (targets.length === 0) return;
      const lookups = await Promise.all(targets.map(async (u) => {
        try {
          const name = await getEnsName(config, { address: u.address as `0x${string}` });
          return { address: u.address, ensName: name || undefined };
        } catch {
          return { address: u.address, ensName: undefined };
        }
      }));
      const ensByAddress = new Map<string, string | undefined>(lookups.map(l => [l.address, l.ensName]));
      const enrichedUsers: User[] = allUsers.map(u => {
        const ensName = ensByAddress.get(u.address);
        if (ensName) {
          return {
            ...u,
            walletType: 'ethereum',
            ensOwnership: true,
            ensName,
            verificationStatus: 'verified-owner'
          } as User;
        }
        return u;
      });
      const enrichedStatus = relevanceCalculator.buildUserVerificationStatus(enrichedUsers);
      const transformed = getDataFromCache(verifyFn, enrichedStatus);
      setCells(transformed.cells);
      setPosts(transformed.posts);
      setComments(transformed.comments);
      setUserVerificationStatus(enrichedStatus);
    })();
  }, [cryptoService, isAuthenticated, currentUser]);
  
  const handleRefreshData = async () => {
    setIsRefreshing(true);
    try {
      // Manually query the network for updates
      await messageManager.queryStore();
      updateStateFromCache();
    } catch (error) {
      console.error("Error refreshing data:", error);
      toast({
        title: "Refresh Failed",
        description: "Could not fetch the latest data. Please try again.",
        variant: "destructive",
      });
    } finally {
      setIsRefreshing(false);
    }
  };

  // Monitor network connection status
  useEffect(() => {
    const { unsubscribe } = monitorNetworkHealth(setIsNetworkConnected, toast);
    return unsubscribe;
  }, [toast]);

  useEffect(() => {
    const loadData = async () => {
      setIsInitialLoading(true);
      await initializeNetwork(toast, updateStateFromCache, setError);
      setIsInitialLoading(false);
    };

    loadData();

    // Set up periodic queries
    const { cleanup } = setupPeriodicQueries(isNetworkConnected, updateStateFromCache);

    return cleanup;
  }, [isNetworkConnected, toast, updateStateFromCache]);

  const getCellById = (id: string): Cell | undefined => {
    return cells.find(cell => cell.id === id);
  };

  const getPostsByCell = (cellId: string): Post[] => {
    return posts.filter(post => post.cellId === cellId)
      .sort((a, b) => b.timestamp - a.timestamp);
  };

  const getCommentsByPost = (postId: string): Comment[] => {
    return comments.filter(comment => comment.postId === postId)
      .sort((a, b) => a.timestamp - b.timestamp);
  };

  const handleCreatePost = async (cellId: string, title: string, content: string): Promise<Post | null> => {
    setIsPostingPost(true);
    const result = await createPost(
      cellId, 
      title, 
      content, 
      currentUser, 
      isAuthenticated, 
      toast, 
      updateStateFromCache,
      authService
    );
    setIsPostingPost(false);
    return result;
  };

  const handleCreateComment = async (postId: string, content: string): Promise<Comment | null> => {
    setIsPostingComment(true);
    const result = await createComment(
      postId, 
      content, 
      currentUser, 
      isAuthenticated, 
      toast, 
      updateStateFromCache,
      authService
    );
    setIsPostingComment(false);
    return result;
  };

  const handleVotePost = async (postId: string, isUpvote: boolean): Promise<boolean> => {
    setIsVoting(true);
    const result = await vote(
      postId, 
      isUpvote, 
      currentUser, 
      isAuthenticated, 
      toast, 
      updateStateFromCache,
      authService
    );
    setIsVoting(false);
    return result;
  };

  const handleVoteComment = async (commentId: string, isUpvote: boolean): Promise<boolean> => {
    setIsVoting(true);
    const result = await vote(
      commentId, 
      isUpvote, 
      currentUser, 
      isAuthenticated, 
      toast, 
      updateStateFromCache,
      authService
    );
    setIsVoting(false);
    return result;
  };

  const handleCreateCell = async (name: string, description: string, icon?: string): Promise<Cell | null> => {
    setIsPostingCell(true);
    const result = await createCell(
      name, 
      description, 
      icon, 
      currentUser, 
      isAuthenticated, 
      toast, 
      updateStateFromCache,
      authService
    );
    setIsPostingCell(false);
    return result;
  };

  const handleModeratePost = async (
    cellId: string,
    postId: string,
    reason: string | undefined,
    cellOwner: string
  ) => {
    return moderatePost(
      cellId,
      postId,
      reason,
      currentUser,
      isAuthenticated,
      cellOwner,
      toast,
      updateStateFromCache,
      authService
    );
  };

  const handleModerateComment = async (
    cellId: string,
    commentId: string,
    reason: string | undefined,
    cellOwner: string
  ) => {
    return moderateComment(
      cellId,
      commentId,
      reason,
      currentUser,
      isAuthenticated,
      cellOwner,
      toast,
      updateStateFromCache,
      authService
    );
  };

  const handleModerateUser = async (
    cellId: string,
    userAddress: string,
    reason: string | undefined,
    cellOwner: string
  ) => {
    return moderateUser(
      cellId,
      userAddress,
      reason,
      currentUser,
      isAuthenticated,
      cellOwner,
      toast,
      updateStateFromCache,
      authService
    );
  };

  return (
    <ForumContext.Provider
      value={{
        cells,
        posts,
        comments,
        userVerificationStatus,
        isInitialLoading,
        isPostingCell,
        isPostingPost,
        isPostingComment,
        isVoting,
        isRefreshing,
        isNetworkConnected,
        error,
        getCellById,
        getPostsByCell,
        getCommentsByPost,
        createPost: handleCreatePost,
        createComment: handleCreateComment,
        votePost: handleVotePost,
        voteComment: handleVoteComment,
        createCell: handleCreateCell,
        refreshData: handleRefreshData,
        moderatePost: handleModeratePost,
        moderateComment: handleModerateComment,
        moderateUser: handleModerateUser
      }}
    >
      {children}
    </ForumContext.Provider>
  );
}


