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

// Dependencies interface for easier testing
export interface SendSlackMessageDependencies {
  WebClient: typeof WebClient
  getSlackToken: () => string | undefined
  getSlackChannelId: () => string | undefined
  console: typeof console
}

// Default dependencies
let dependencies: SendSlackMessageDependencies = {
  WebClient,
  getSlackToken: () => process.env.SLACK_TOKEN,
  getSlackChannelId: () => process.env.SLACK_CHANNEL_ID,
  console,
}

// For testing - allow dependency injection
export function setSendSlackMessageDependencies(deps: Partial<SendSlackMessageDependencies>) {
  dependencies = { ...dependencies, ...deps }
}

export function resetSendSlackMessageDependencies() {
  dependencies = {
    WebClient,
    getSlackToken: () => process.env.SLACK_TOKEN,
    getSlackChannelId: () => process.env.SLACK_CHANNEL_ID,
    console,
  }
}

// Initialize web client
let web: WebClient | null = null

export function initializeWebClient() {
  const SLACK_TOKEN = dependencies.getSlackToken()
  const SLACK_CHANNEL_ID = dependencies.getSlackChannelId()

  if (!SLACK_TOKEN) {
    throw new Error("Missing SLACK_TOKEN")
  }

  if (!SLACK_CHANNEL_ID) {
    throw new Error("Missing SLACK_CHANNEL_ID")
  }

  web ||= new dependencies.WebClient(SLACK_TOKEN, {})

  return web
}

// For testing - allow resetting the web client
export function resetWebClient() {
  web = null
}

/**
 * Send a message to Slack
 *
 * @param {string|object} message - Text message or Block Kit message object
 * @param {string|null} channel - Channel ID, defaults to SLACK_CHANNEL_ID
 * @param {boolean} returnData - Whether to return the full Slack API response
 * @returns {Promise<boolean|object>} - True or API response
 */
export const sendSlackMessage = async (
  message: any,
  channel: string | null = null,
  returnData: boolean = false,
): Promise<boolean | object> =>
  await new Promise(async (resolve, reject) => {
    try {
      const webClient = initializeWebClient()
      const SLACK_CHANNEL_ID = dependencies.getSlackChannelId()
      const channelId = channel || SLACK_CHANNEL_ID

      // Configure the message payload depending on the input type
      let payload: ChatPostMessageArguments

      if (typeof message === "string") {
        payload = {
          channel: channelId,
          text: message,
        }
      } else if (message && typeof message === "object") {
        if (message.blocks) {
          payload = {
            channel: channelId,
            text: message.text || "Notification from CodeFlash",
            blocks: message.blocks,
          }
        } else {
          dependencies.console.warn("Object passed to sendSlackMessage without blocks property")
          payload = {
            channel: channelId,
            text: JSON.stringify(message),
          }
        }
      } else {
        dependencies.console.error("Invalid message type", typeof message)
        payload = {
          channel: channelId,
          text: "Invalid message",
        }
      }

      // console.log("Sending payload to Slack:", JSON.stringify(payload, null, 2));

      const resp = await webClient.chat.postMessage(payload)
      resolve(returnData ? resp : true)
    } catch (error) {
      dependencies.console.error("Error sending Slack message:", error)
      resolve(returnData ? { error } : true)
    }
  })
