import { WebClient } from "@slack/web-api";

export class SlackService {
  private client: WebClient;
  private vettingChannelId: string;

  constructor(botToken: string, vettingChannelId: string) {
    this.client = new WebClient(botToken);
    this.vettingChannelId = vettingChannelId;
  }

  /**
   * Invite user to workspace and channel (using proper admin and conversation scopes)
   */
  async inviteUserToSlack(
    email: string,
    realName: string,
  ): Promise<{
    success: boolean;
    userId?: string;
    status?: string;
    error?: string;
  }> {
    try {
      // First, check if user already exists in workspace
      const existingUser = await this.findUserByEmail(email);

      if (existingUser) {
        // User exists, invite them to the vetting channel
        try {
          await this.client.conversations.invite({
            channel: this.vettingChannelId,
            users: existingUser,
          });

          console.log(
            `Successfully invited existing user ${email} to vetting channel`,
          );
          return {
            success: true,
            userId: existingUser,
            status: "existing_user_added_to_channel",
          };
        } catch (error: any) {
          if (error.data?.error === "already_in_channel") {
            return {
              success: true,
              userId: existingUser,
              status: "user_already_in_channel",
            };
          }
          throw error;
        }
      }

      // User doesn't exist, try to invite to workspace using admin API
      try {
        const inviteResponse = await this.client.admin.users.invite({
          email: email,
          real_name: realName,
          channel_ids: [this.vettingChannelId],
          is_restricted: true, // Single-channel guest
          is_ultra_restricted: false,
        });

        if (inviteResponse.ok && inviteResponse.user) {
          console.log(
            `Successfully invited ${email} to workspace as single-channel guest`,
          );
          return {
            success: true,
            userId: inviteResponse.user.id,
            status: "new_user_invited_to_workspace",
          };
        } else {
          throw new Error(`Admin invite failed: ${inviteResponse.error}`);
        }
      } catch (adminError: any) {
        console.log(
          `Admin API not available or failed: ${
            adminError.data?.error || adminError.message
          }`,
        );

        // Fall back to manual process
        return {
          success: true,
          status: "manual_invitation_required",
          error: `Admin API unavailable: ${
            adminError.data?.error || adminError.message
          }`,
        };
      }
    } catch (error: any) {
      console.error(`Failed to process invitation for ${email}:`, error);

      return {
        success: false,
        error: error.data?.error || error.message || "Unknown error occurred",
      };
    }
  }

  /**
   * Find user in workspace by email
   */
  private async findUserByEmail(email: string): Promise<string | null> {
    try {
      const response = await this.client.users.lookupByEmail({ email });
      return response.user?.id || null;
    } catch {
      return null;
    }
  }

  /**
   * Find user ID by username (display name or real name)
   */
  async findUserIdByUsername(username: string): Promise<string | null> {
    try {
      const cleanUsername = username.replace("@", "").toLowerCase();

      // List all users and search for matching username
      const response = await this.client.users.list();

      if (!response.members) {
        return null;
      }

      // Search for user by name or display_name
      const user = response.members.find((member: any) => {
        const name = member.name?.toLowerCase() || "";
        const realName = member.real_name?.toLowerCase() || "";
        const displayName = member.profile?.display_name?.toLowerCase() || "";

        return (
          name === cleanUsername ||
          displayName === cleanUsername ||
          realName.includes(cleanUsername)
        );
      });

      return user?.id || null;
    } catch (error) {
      console.error("Error looking up Slack user by username:", error);
      return null;
    }
  }

  /**
   * Open/get a DM channel with a user and return the channel ID
   * This creates or opens a DM conversation and returns the channel ID (starts with D)
   */
  async openDMChannel(userId: string): Promise<string | null> {
    try {
      const response = await this.client.conversations.open({
        users: userId,
      });

      if (response.ok && response.channel?.id) {
        console.log(
          `Opened DM channel for user ${userId}: ${response.channel.id}`,
        );
        return response.channel.id;
      }

      return null;
    } catch (error: any) {
      console.error(
        "Error opening DM channel:",
        error.data?.error || error.message,
      );
      return null;
    }
  }

  /**
   * Send a notification to the vetting channel about a new member
   */
  async notifyNewMember(
    memberName: string,
    memberEmail: string,
    circle: string,
    contributionTier: string,
    invitationStatus: string = "manual_invitation_required",
  ): Promise<void> {
    try {
      let statusMessage = "";
      let actionMessage = "";

      switch (invitationStatus) {
        case "existing_user_added_to_channel":
          statusMessage =
            "✅ Existing user automatically added to this channel.";
          actionMessage = "Ready for vetting!";
          break;
        case "user_already_in_channel":
          statusMessage = "✅ User is already in this channel.";
          actionMessage = "Ready for vetting!";
          break;
        case "new_user_invited_to_workspace":
          statusMessage =
            "🎉 User successfully invited to workspace as single-channel guest.";
          actionMessage = "Ready for vetting!";
          break;
        case "manual_invitation_required":
          statusMessage = "📧 User needs to be manually invited to join Slack.";
          actionMessage = `Please vet this new member before inviting them to other channels.`;
          break;
        default:
          statusMessage = "⚠️ Invitation status unknown.";
          actionMessage = "Manual review required.";
      }

      await this.client.chat.postMessage({
        channel: this.vettingChannelId,
        text: `New Ghost Guild member: ${memberName}`,
        blocks: [
          {
            type: "header",
            text: {
              type: "plain_text",
              text: "New Ghost Guild Member Registration",
            },
          },
          {
            type: "section",
            fields: [
              {
                type: "mrkdwn",
                text: `*Name:*\n${memberName}`,
              },
              {
                type: "mrkdwn",
                text: `*Email:*\n${memberEmail}`,
              },
              {
                type: "mrkdwn",
                text: `*Circle:*\n${circle}`,
              },
              {
                type: "mrkdwn",
                text: `*Contribution:*\n$${contributionTier}/month`,
              },
            ],
          },
          {
            type: "section",
            text: {
              type: "mrkdwn",
              text: `*Status:* ${statusMessage}\n*Action:* ${actionMessage}`,
            },
          },
          {
            type: "divider",
          },
        ],
      });
    } catch (error) {
      console.error("Failed to send Slack notification:", error);
      // Don't throw - this is non-critical
    }
  }

  /**
   * Verify the Slack channel exists and bot has access
   */
  async verifyChannelAccess(): Promise<boolean> {
    try {
      const response = await this.client.conversations.info({
        channel: this.vettingChannelId,
      });
      return response.ok && !!response.channel;
    } catch {
      return false;
    }
  }
}

/**
 * Get configured Slack service instance
 */
export function getSlackService(): SlackService | null {
  const config = useRuntimeConfig();

  if (!config.slackBotToken || !config.slackVettingChannelId) {
    console.warn(
      "Slack integration not configured - missing bot token or channel ID",
    );
    return null;
  }

  return new SlackService(config.slackBotToken, config.slackVettingChannelId);
}
