import React, { createContext, useContext, useEffect, useState } from "react";

const API_BASE = import.meta.env.VITE_API_BASE || "";

interface DiscordUser {
  id: string;
  discord_id: string;
  full_name: string | null;
  username: string | null;
  avatar_url: string | null;
  bio: string | null;
  user_type: string | null;
  primary_arm: string | null;
}

interface Participant {
  id: string;
  username: string;
  discriminator: string;
  avatar: string | null;
  bot: boolean;
  flags: number;
  global_name: string | null;
}

interface VoiceState {
  mute: boolean;
  deaf: boolean;
  self_mute: boolean;
  self_deaf: boolean;
  suppress: boolean;
}

interface ParticipantWithVoice extends Participant {
  voice_state?: VoiceState;
  speaking?: boolean;
}

interface DiscordActivityContextType {
  isActivity: boolean;
  isLoading: boolean;
  user: DiscordUser | null;
  error: string | null;
  discordSdk: any | null;
  participants: ParticipantWithVoice[];
  channelId: string | null;
  guildId: string | null;
  openExternalLink: (url: string) => Promise<void>;
}

const DiscordActivityContext = createContext<DiscordActivityContextType>({
  isActivity: false,
  isLoading: false,
  user: null,
  error: null,
  discordSdk: null,
  participants: [],
  channelId: null,
  guildId: null,
  openExternalLink: async () => {},
});

export const useDiscordActivity = () => {
  const context = useContext(DiscordActivityContext);
  if (!context) {
    throw new Error(
      "useDiscordActivity must be used within DiscordActivityProvider",
    );
  }
  return context;
};

interface DiscordActivityProviderProps {
  children: React.ReactNode;
}

export const DiscordActivityProvider: React.FC<
  DiscordActivityProviderProps
> = ({ children }) => {
  const [isActivity, setIsActivity] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [user, setUser] = useState<DiscordUser | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [discordSdk, setDiscordSdk] = useState<any>(null);
  const [auth, setAuth] = useState<any>(null);
  const [participants, setParticipants] = useState<ParticipantWithVoice[]>([]);
  const [channelId, setChannelId] = useState<string | null>(null);
  const [guildId, setGuildId] = useState<string | null>(null);
  const [speakingUsers, setSpeakingUsers] = useState<Set<string>>(new Set());

  useEffect(() => {
    const initializeActivity = async () => {
      // Check if we're running inside a Discord Activity
      // Discord passes frame_id as a query parameter when launching an Activity
      if (typeof window === "undefined") {
        return; // Skip on server-side
      }

      const searchParams = new URLSearchParams(window.location.search);
      const frameId = searchParams.get("frame_id");
      const isInDiscordActivity = frameId !== null;

      console.log("[Discord Activity] Checking for Discord context...", {
        frameId,
        isInDiscordActivity,
      });

      // If we're NOT in Discord Activity, exit early - don't load Discord SDK
      if (!isInDiscordActivity) {
        console.log(
          "[Discord Activity] Not in Discord Activity - skipping SDK load",
        );
        setIsActivity(false);
        setIsLoading(false);
        return;
      }

      // Only initialize Discord SDK if we're actually in a Discord Activity
      if (isInDiscordActivity) {
        try {
          setIsActivity(true);
          setIsLoading(true);

          // Import the Discord SDK dynamically
          const { DiscordSDK } = await import("@discord/embedded-app-sdk");

          const clientId =
            import.meta.env.VITE_DISCORD_CLIENT_ID || "578971245454950421";

          console.log(
            "[Discord Activity] Creating SDK with clientId:",
            clientId,
          );

          const sdk = new DiscordSDK(clientId);

          setDiscordSdk(sdk);

          // Wait for SDK to be ready
          console.log("[Discord Activity] Waiting for SDK to be ready...");
          await sdk.ready();
          console.log("[Discord Activity] SDK is ready");

          // Authorize the user to get an access token
          console.log("[Discord Activity] Authorizing user...");
          const { code } = await sdk.commands.authorize({
            client_id: clientId,
            response_type: "code",
            state: "",
            scope: ["identify", "guilds"],
            prompt: "none",
          });

          console.log(
            "[Discord Activity] Got authorization code, exchanging for token...",
          );

          // Exchange code for access token via our backend
          const tokenResponse = await fetch(`${API_BASE}/api/discord/token`, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({ code }),
          });

          if (!tokenResponse.ok) {
            const errorData = await tokenResponse.json();
            const errMsg = errorData.error || "Failed to exchange code";
            console.error(
              "[Discord Activity] Token exchange failed:",
              errMsg,
            );
            setError(errMsg);
            setIsLoading(false);
            return;
          }

          const tokenData = await tokenResponse.json();
          const access_token = tokenData.access_token;

          console.log(
            "[Discord Activity] Got access token, authenticating with SDK...",
          );

          // Authenticate with SDK using the access token
          const authResult = await sdk.commands.authenticate({
            access_token,
          });

          if (!authResult) {
            console.error("[Discord Activity] SDK authentication failed");
            setError("SDK authentication failed");
            setIsLoading(false);
            return;
          }

          console.log(
            "[Discord Activity] Authenticated with SDK, fetching user profile...",
          );
          setAuth(authResult);

          // Get user info using the access token
          const userResponse = await fetch(
            "https://discord.com/api/v10/users/@me",
            {
              headers: {
                Authorization: `Bearer ${access_token}`,
              },
            },
          );

          if (!userResponse.ok) {
            console.error("[Discord Activity] Failed to fetch user profile");
            setError("Failed to fetch user profile");
            setIsLoading(false);
            return;
          }

          const discordUserData = await userResponse.json();
          console.log(
            "[Discord Activity] User profile fetched:",
            discordUserData.username,
          );

          // Store the user data
          const userData: DiscordUser = {
            id: discordUserData.id,
            discord_id: discordUserData.id,
            full_name:
              discordUserData.global_name || discordUserData.username,
            username: discordUserData.username,
            avatar_url: discordUserData.avatar
              ? `https://cdn.discordapp.com/avatars/${discordUserData.id}/${discordUserData.avatar}.png`
              : null,
            bio: null,
            user_type: "community_member",
            primary_arm: "labs",
          };

          setUser(userData);
          setError(null);
          console.log("[Discord Activity] User authenticated successfully");

          // Store channel and guild info
          setChannelId(sdk.channelId);
          setGuildId(sdk.guildId);

          // Fetch initial participants
          try {
            console.log("[Discord Activity] Fetching participants...");
            const participantsResult = await sdk.commands.getInstanceConnectedParticipants();
            if (participantsResult?.participants) {
              const participantList = participantsResult.participants.map((p: any) => ({
                id: p.id,
                username: p.username,
                discriminator: p.discriminator || "0",
                avatar: p.avatar,
                bot: p.bot || false,
                flags: p.flags || 0,
                global_name: p.global_name,
              }));
              setParticipants(participantList);
              console.log("[Discord Activity] Initial participants:", participantList.length);
            }

            // Subscribe to participant updates
            sdk.subscribe("ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE", (data: any) => {
              console.log("[Discord Activity] Participants updated:", data);
              if (data?.participants) {
                const updatedList = data.participants.map((p: any) => ({
                  id: p.id,
                  username: p.username,
                  discriminator: p.discriminator || "0",
                  avatar: p.avatar,
                  bot: p.bot || false,
                  flags: p.flags || 0,
                  global_name: p.global_name,
                }));
                setParticipants(updatedList);
              }
            });

            // Subscribe to speaking updates if in voice channel
            if (sdk.channelId) {
              try {
                sdk.subscribe("SPEAKING_START", (data: any) => {
                  console.log("[Discord Activity] Speaking start:", data);
                  if (data?.user_id) {
                    setSpeakingUsers(prev => new Set(prev).add(data.user_id));
                    setParticipants(prev => prev.map(p => 
                      p.id === data.user_id ? { ...p, speaking: true } : p
                    ));
                  }
                }, { channel_id: sdk.channelId });

                sdk.subscribe("SPEAKING_STOP", (data: any) => {
                  console.log("[Discord Activity] Speaking stop:", data);
                  if (data?.user_id) {
                    setSpeakingUsers(prev => {
                      const next = new Set(prev);
                      next.delete(data.user_id);
                      return next;
                    });
                    setParticipants(prev => prev.map(p => 
                      p.id === data.user_id ? { ...p, speaking: false } : p
                    ));
                  }
                }, { channel_id: sdk.channelId });

                console.log("[Discord Activity] Voice subscriptions active");
              } catch (voiceErr) {
                console.log("[Discord Activity] Voice subscription not available:", voiceErr);
              }
            }
          } catch (participantErr) {
            console.log("[Discord Activity] Could not fetch participants:", participantErr);
          }
        } catch (err: any) {
          console.error("Discord Activity initialization error:", err);
          console.error("Error details:", {
            message: err?.message,
            code: err?.code,
            stack: err?.stack,
          });
          setError(
            `${err?.message || "Failed to initialize Discord Activity"}. Check browser console for details.`,
          );
        } finally {
          setIsLoading(false);
        }
      } else {
        // Not in a Discord iframe
        console.log(
          "[Discord Activity] Not in Discord Activity context (no frame_id)",
        );
        setIsActivity(false);
        setIsLoading(false);
      }
    };

    initializeActivity();
  }, []);

  const openExternalLink = async (url: string) => {
    if (discordSdk) {
      try {
        await discordSdk.commands.openExternalLink({ url });
      } catch (err) {
        console.error("[Discord Activity] Failed to open external link:", err);
        window.open(url, "_blank");
      }
    } else {
      window.open(url, "_blank");
    }
  };

  return (
    <DiscordActivityContext.Provider
      value={{
        isActivity,
        isLoading,
        user,
        error,
        discordSdk,
        participants,
        channelId,
        guildId,
        openExternalLink,
      }}
    >
      {children}
    </DiscordActivityContext.Provider>
  );
};

export default DiscordActivityContext;
