const { EmbedBuilder } = require("discord.js");
const Logger = require("../utils/Logger");

class SubscriptionCommands {
  constructor(supabase, supabaseService) {
    
    this.logger = new Logger("SubscriptionCommands");
    
    this.supabase = supabase;

    this.supabaseService = supabaseService;

    if (!this.supabase) {
      throw new Error("Supabase client not initialized");
    }
  }

  async handleSubscribe(interaction) {
    try {
        // Verify interaction is already deferred
        if (!interaction.deferred) {
            this.logger.warn("Interaction not deferred before handleSubscribe");
            return;
        }

        const gameName = this.sanitizeInput(
            interaction.options.getString("game")
        );
        const channel = interaction.options.getChannel("channel");
        const guildId = interaction.guildId;
        const serverName = this.sanitizeInput(interaction.guild.name);

        this.logger.debug("Starting subscription process", {
            gameName,
            channelId: channel?.id,
            guildId,
            serverName,
        });
  
      // Input validation
      if (!gameName || gameName.length === 0) {
        await interaction.editReply("Invalid game name provided.");
        return;
      }
  
      if (!channel) {
        await interaction.editReply("Invalid channel selected.");
        return;
      }
  
      // Get or create server
      let server;
      try {
        server = await this.getOrCreateServer(guildId, serverName);
      } catch (error) {
        this.logger.error("Failed to get/create server", {
          error: error.message,
          guildId,
          serverName,
        });
        await interaction.editReply(
          "Failed to register server. Please try again later."
        );
        return;
      }
  
      // Get game data
      const gameData = await this.getGame(gameName);
      if (!gameData) {
        await interaction.editReply(
          `Game "${gameName}" not found or is not currently supported.`
        );
        return;
      }
  
      // Check for existing subscription
      const existingSubscription = await this.verifySubscription(
        server.id,
        gameData.id
      );
  
      // Create or update subscription
      const subscriptionResult = await this.createOrUpdateSubscription(
        server.id,
        gameData.id,
        channel.id
      );
  
      if (!subscriptionResult) {
        await interaction.editReply(
          "Failed to save subscription. Please try again later."
        );
        return;
      }
  
      // Success response
      const successMessage = existingSubscription
        ? `Updated subscription for ${gameName} to channel ${channel}.`
        : `Successfully subscribed to ${gameName} notifications in ${channel}.`;
  
      await interaction.editReply(successMessage);
  
    } catch (error) {
        this.logger.error("Error in handleSubscribe:", {
            error: error.message,
            stack: error.stack,
            interaction: {
                guildId: interaction.guildId,
                channelId: interaction.channelId,
            }
        });
        
        if (interaction.deferred && !interaction.replied) {
            await interaction.editReply(
                "An unexpected error occurred. Please try again later."
            );
        }
    }
}

  // Helper methods

  async checkExistingSubscription(serverId, gameId) {
    try {
      const { data, error } = await this.supabase
        .from("server_game_preferences")
        .select("*")
        .eq("server_id", serverId)
        .eq("game_id", gameId)
        .single();

      if (error && error.code !== "PGRST116") {
        // PGRST116 is "no rows returned"
        this.logger.error("Error checking existing subscription:", error);
        return null;
      }

      return data;
    } catch (error) {
      this.logger.error("Error in checkExistingSubscription:", {
        error: error.message,
        stack: error.stack,
      });
      return null;
    }
  }

  async verifySubscription(serverId, gameId) {
    try {
        const { data, error } = await this.supabase
            .from("server_game_preferences")
            .select("*")
            .eq("server_id", serverId)
            .eq("game_id", gameId)
            .single();

        if (error) {
            if (error.code === "PGRST116") {
                // No rows found is not an error in this context
                this.logger.debug("No existing subscription found", {
                    serverId,
                    gameId
                });
                return null;
            }
            
            this.logger.error("Error verifying subscription:", error);
            return null;
        }

        return data;
    } catch (error) {
        this.logger.error("Error in verifySubscription:", {
            error: error.message,
            stack: error.stack,
        });
        return null;
    }
}

  async handleUnsubscribe(interaction) {
    try {
      const gameName = this.sanitizeInput(
        interaction.options.getString("game")
      );
      const guildId = interaction.guildId;

      if (!gameName || gameName.length === 0) {
        await this.safeReply(interaction, "Invalid game name provided.");
        return;
      }

      this.logger.debug("Processing unsubscribe request", {
        game: gameName,
        guildId,
      });

      const subscription = await this.fetchSubscription(guildId, gameName);
      if (!subscription) {
        await this.safeReply(
          interaction,
          `No subscription found for ${gameName}.`
        );
        return;
      }

      this.logger.debug("Subscription to delete", { subscription });

      const success = await this.deleteSubscription(subscription);
      if (success) {
        await this.safeReply(
          interaction,
          `Successfully unsubscribed from ${gameName} notifications.`
        );
      } else {
        await this.safeReply(
          interaction,
          `Failed to unsubscribe from ${gameName} notifications. Please try again later.`
        );
      }
    } catch (error) {
      this.logger.error("Error in handleUnsubscribe:", {
        error,
        stack: error.stack,
      });
      await this.safeReply(
        interaction,
        "An unexpected error occurred. Please try again later."
      );
    }
  }

  async handleListSubscriptions(interaction) {
    try {
      const guildId = interaction.guildId;
      this.logger.debug("Fetching subscriptions", { guildId });

      const subscriptions = await this.getSubscriptions(guildId);
      
      if (!subscriptions || subscriptions.length === 0) {
        await interaction.editReply({
          content: "📝 This server has no game subscriptions.",
          ephemeral: true
        });
        return;
      }

      const embed = new EmbedBuilder()
        .setColor("#0099ff")
        .setTitle("🎮 Game Subscriptions")
        .setDescription("Current game notification subscriptions for this server:")
        .addFields(
          subscriptions.map((sub) => ({
            name: `${sub.game_name || 'Unknown Game'}`,
            value: sub.notification_channel_id ? `<#${sub.notification_channel_id}>` : 'No channel set',
            inline: true,
          }))
        )
        .setTimestamp()
        .setFooter({ text: "VRBattles Match System" });

      await interaction.editReply({
        embeds: [embed],
        ephemeral: true
      });
    } catch (error) {
      this.logger.error("Error in handleListSubscriptions:", {
        error: error.message,
        stack: error.stack,
        guildId: interaction.guildId
      });

      await interaction.editReply({
        content: "❌ An error occurred while fetching subscriptions.",
        ephemeral: true
      });
    }
  }

  async getSubscriptions(guildId) {
    try {
      const { data: subscriptions, error } = await this.supabase
        .from("active_subscriptions")
        .select("*")
        .eq("discord_server_id", guildId);

      if (error) {
        this.logger.error("Error fetching subscriptions", { error });
        return null;
      }

      return subscriptions;
    } catch (error) {
      this.logger.error("Error in getSubscriptions:", {
        error: error.message,
        stack: error.stack,
        guildId
      });
      return null;
    }
  }

  // Helper Methods
  async testSupabaseConnection() {
    try {
      const { data, error } = await this.supabase
        .from("servers")
        .select("id")
        .limit(1);

      if (error) {
        this.logger.error("Supabase connection test failed:", { error });
        return false;
      }

      this.logger.debug("Supabase connection test successful", { data });
      return true;
    } catch (error) {
      this.logger.error("Unexpected error in Supabase connection test:", {
        error,
        stack: error.stack,
      });
      return false;
    }
  }

  async getOrCreateServer(guildId, serverName) {
    try {
      this.logger.debug("Starting getOrCreateServer", {
        guildId,
        serverName,
        timestamp: new Date().toISOString(),
      });
  
      // First attempt to get existing server
      const { data: existingServer, error: checkError } = await this.supabase
        .from("servers")
        .select("*")
        .eq("discord_server_id", guildId)
        .single();
  
      this.logger.debug("Server lookup result", {
        exists: !!existingServer,
        error: checkError ? {
          message: checkError.message,
          code: checkError.code,
          details: checkError.details,
        } : null,
      });
  
      // If server exists and is active, return it
      if (existingServer) {
        this.logger.debug("Using existing server", {
          serverId: existingServer.id,
          serverDetails: existingServer,
        });
        return existingServer;
      }
  
      // If no server exists, create one with exact schema match
      const { data: newServer, error: insertError } = await this.supabase
        .from("servers")
        .insert([
          {
            discord_server_id: guildId,
            server_name: serverName,
            active: true,
            // created_at will be handled by Supabase automatically
          }
        ])
        .select()
        .single();
  
      if (insertError) {
        this.logger.error("Server creation failed", {
          error: insertError,
          details: {
            code: insertError.code,
            message: insertError.message,
          },
          attemptedData: { guildId, serverName },
        });
        throw new Error(`Failed to create server: ${insertError.message}`);
      }
  
      this.logger.info("New server created successfully", {
        serverId: newServer.id,
        serverDetails: newServer,
      });
  
      return newServer;
    } catch (error) {
      this.logger.error("Unexpected error in getOrCreateServer", {
        error: error.message,
        stack: error.stack,
        guildId,
        serverName,
      });
      throw error;
    }
  }

  async getGame(gameName) {
    try {
      const sanitizedGameName = this.sanitizeInput(gameName);
      const { data: gameData, error: gameError } = await this.supabase
        .from("games")
        .select("id, name")
        .eq("name", sanitizedGameName)
        .eq("active", true)
        .single();

      if (gameError || !gameData) {
        this.logger.error("Error fetching game data:", {
          gameError,
          gameName: sanitizedGameName,
        });
        return null;
      }

      return gameData;
    } catch (error) {
      this.logger.error("Error in getGame:", { error, stack: error.stack });
      return null;
    }
  }

  async createOrUpdateSubscription(serverId, gameId, channelId) {
    try {
      const { data: prefData, error: prefError } = await this.supabase
        .from("server_game_preferences")
        .upsert(
          {
            server_id: serverId,
            game_id: gameId,
            notification_channel_id: channelId,
          },
          { onConflict: "server_id,game_id" }
        )
        .select();

      if (prefError) {
        this.logger.error("Error creating/updating subscription:", {
          prefError,
          serverId,
          gameId,
          channelId,
        });
        return null;
      }

      return prefData;
    } catch (error) {
      this.logger.error("Error in createOrUpdateSubscription:", {
        error,
        stack: error.stack,
      });
      return null;
    }
  }

  async getGame(gameName, interaction) {
    try {
      const { data: gameData, error: gameError } = await this.supabase
        .from("games")
        .select("id, name")
        .eq("name", gameName)
        .eq("active", true)
        .single();

      if (gameError || !gameData) {
        this.logger.error("Error fetching game data:", { gameError, gameName });
        return null;
      }

      return gameData;
    } catch (error) {
      this.logger.error("Error in getGame:", { error, stack: error.stack });
      return null;
    }
  }

  async createOrUpdateSubscription(serverId, gameId, channelId, interaction) {
    try {
      const { data: prefData, error: prefError } = await this.supabase
        .from("server_game_preferences")
        .upsert(
          {
            server_id: serverId,
            game_id: gameId,
            notification_channel_id: channelId,
          },
          { onConflict: "server_id,game_id" }
        )
        .select();

      if (prefError) {
        this.logger.error("Error creating/updating subscription:", {
          prefError,
          serverId,
          gameId,
          channelId,
        });
        return null;
      }

      return prefData;
    } catch (error) {
      this.logger.error("Error in createOrUpdateSubscription:", {
        error,
        stack: error.stack,
      });
      return null;
    }
  }

  async fetchSubscription(guildId, gameName) {
    // Fetch the subscription data
    const { data: subscription, error: subError } = await this.supabase
      .from("active_subscriptions")
      .select("*")
      .eq("discord_server_id", guildId)
      .eq("game_name", gameName)
      .single();

    if (subError || !subscription) {
      this.logger.debug("No subscription found", { guildId, gameName });
      return null;
    }

    // Fetch the server_id
    const { data: serverData, error: serverError } = await this.supabase
      .from("servers")
      .select("id")
      .eq("discord_server_id", guildId)
      .single();

    if (serverError) {
      this.logger.error("Error fetching server_id", { serverError });
      return null;
    }

    // Fetch the game_id
    const { data: gameData, error: gameError } = await this.supabase
      .from("games")
      .select("id")
      .eq("name", gameName)
      .single();

    if (gameError) {
      this.logger.error("Error fetching game_id", { gameError });
      return null;
    }

    this.logger.debug("Subscription fetched", {
      subscription,
      serverData,
      gameData,
    });
    return {
      server_id: serverData.id,
      game_id: gameData.id,
      discord_server_id: subscription.discord_server_id,
      game_name: subscription.game_name,
      notification_channel_id: subscription.notification_channel_id,
    };
  }

  async deleteSubscription(subscription) {
    if (!subscription || !subscription.server_id || !subscription.game_id) {
      this.logger.error("Invalid subscription data", {
        subscription,
        hasServerId: !!subscription?.server_id,
        hasGameId: !!subscription?.game_id,
      });
      return false;
    }

    const { error: deleteError } = await this.supabase
      .from("server_game_preferences")
      .delete()
      .match({
        server_id: subscription.server_id,
        game_id: subscription.game_id,
      });

    if (deleteError) {
      this.logger.error("Delete error", { deleteError, subscription });
      return false;
    }

    this.logger.debug("Subscription deleted", { subscription });
    return true;
  }

  async getSubscriptions(guildId, interaction) {
    const { data: subscriptions, error } = await this.supabase
      .from("active_subscriptions")
      .select("*")
      .eq("discord_server_id", guildId);

    if (error) {
      this.logger.error("Error fetching subscriptions", { error });
      await interaction.editReply(
        "Failed to fetch subscriptions. Please try again later."
      );
      return null;
    }

    return subscriptions;
  }
  async safeReply(interaction, content, options = {}) {
    try {
      if (!interaction.deferred && !interaction.replied) {
        await interaction.deferReply({ ephemeral: true });
      }
      
      if (interaction.deferred) {
        await interaction.editReply({ content, ...options });
      }
    } catch (error) {
      this.logger.error("Error in safeReply:", { 
        error: error.message, 
        stack: error.stack,
        interactionStatus: {
          deferred: interaction.deferred,
          replied: interaction.replied
        }
      });
    }
  }

  buildSubscriptionsEmbed(subscriptions) {
    return new EmbedBuilder()
      .setColor("#0099ff")
      .setTitle("Game Subscriptions")
      .setDescription(
        "Current game notification subscriptions for this server:"
      )
      .addFields(
        subscriptions.map((sub) => ({
          name: sub.game_name,
          value: `<#${sub.notification_channel_id}>`,
          inline: true,
        }))
      )
      .setTimestamp()
      .setFooter({ text: "VRBattles Match System" });
  }

  async safeReply(interaction, content, options = {}) {
    try {
      if (!interaction.deferred && !interaction.replied) {
        await interaction.deferReply({ ephemeral: true });
      }

      await interaction.editReply({ content, ...options });
    } catch (error) {
      this.logger.error("Error in safeReply:", { error, stack: error.stack });
    }
  }

  sanitizeInput(input) {
    if (typeof input !== "string") {
      return "";
    }
    // Remove any characters that aren't alphanumeric, spaces, or hyphens
    return input.replace(/[^a-zA-Z0-9 -]/g, "").trim();
  }

  handleError(method, error, interaction) {
    this.logger.error(`Error in ${method}`, { error, stack: error.stack });
    interaction.editReply(
      "An unexpected error occurred. Please try again later."
    );
  }

  validateServerData(guildId, serverName) {
    if (!guildId) {
      this.logger.error("Missing guildId in server data");
      return false;
    }

    if (!serverName) {
      this.logger.error("Missing serverName in server data");
      return false;
    }

    // Validate guildId format (should be a snowflake)
    if (!/^\d+$/.test(guildId)) {
      this.logger.error("Invalid guildId format", { guildId });
      return false;
    }

    // Validate serverName
    if (serverName.length > 100) {
      // Adjust max length based on your database schema
      this.logger.error("Server name too long", { length: serverName.length });
      return false;
    }

    return true;
  }
}

module.exports = SubscriptionCommands;
