import slack_sdk
import re
from blocks import repo
from blocks_control_sdk.utils import get_blocks_runtime_config, patch_blocks_runtime_config, BlocksRuntimeConfigKeys, remove_newlines_and_special_characters
from blocks_control_sdk.blocks_events.context import BLOCKS_EVENT__PROVIDER
from blocks_control_sdk.tools.slack_utils import markdown_to_slack_blocks, create_expandable_quote_block
from blocks_control_sdk.tools.blocks import get_task_header, to_slack_blocks_with_dashboard_button
from blocks_control_sdk.clients.api import Chat, BlocksMessageCreate
import os

SLACK_TOKEN = os.getenv("SLACK_TOKEN")
THRESHOLD_URGENCY_LEVEL = int(os.getenv("THRESHOLD_URGENCY_LEVEL", "5"))


def todo_list_update__slack(body: str, current_task: str, in_progress: bool = True) -> str:
    # update the comment body with the new todo list

    print("="*100)
    print(f"[Action] Sending Todo List Update to Slack")
    print(f"Current task: {current_task}")
    print(f"In progress: {in_progress}")
    print("="*100)

    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    blocks_runtime_config = get_blocks_runtime_config()
    blocks_comment_ts = blocks_runtime_config.get("metadata", {}).get("blocks_comment_ts")
    channel = blocks_runtime_config.get("metadata", {}).get("slack_channel")
    llm_provider_str = blocks_runtime_config.get("llm_provider")

    patch_blocks_runtime_config({
       BlocksRuntimeConfigKeys.LATEST_TODO_LIST: body
    })

    body = f"Blocks has delegated this task to `{llm_provider_str}` Agent\n{':hourglass:' if in_progress else ':white_check_mark:'} {current_task}"
    client.chat_update(
        channel=channel,
        text=body,
        ts=blocks_comment_ts,
        unfurl_links=False,
        unfurl_media=False
    )
    return f"Updated todo list in Slack."

def join_channel__slack(channel: str) -> str:
    print("="*100)
    print(f"[Action] Joining channel: {channel}")
    print("="*100)
    
    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    client.conversations_join(channel=channel)
    return f"Joined channel: {channel}"

def send_message__slack_with_header(message: str, urgency_level_between_zero_to_10: int = 5) -> str:
    print("="*100)
    print(f"[Action] Sending message to user with slack header: {message}")
    print(f"Urgency level: {urgency_level_between_zero_to_10}")
    print("="*100)
    
    if urgency_level_between_zero_to_10 < THRESHOLD_URGENCY_LEVEL:
        return f"This message is not urgent enough to send to the user. Attempt to continue with the task without user input."

    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    blocks_runtime_config = get_blocks_runtime_config()
    blocks_comment_ts = blocks_runtime_config.get("metadata", {}).get("blocks_comment_ts")
    channel = blocks_runtime_config.get("metadata", {}).get("slack_channel")

    message_blocks = to_slack_blocks_with_dashboard_button(get_task_header())
    if message:
        message = remove_newlines_and_special_characters(message)
        blockquote_message = f"> {message}"
        _, additional_blocks = markdown_to_slack_blocks(blockquote_message)
        # Insert additional blocks before the button (which is last)
        message_blocks = message_blocks[:-1] + additional_blocks + [message_blocks[-1]]

    client.chat_update(channel=channel, blocks=message_blocks, ts=blocks_comment_ts, unfurl_links=False, unfurl_media=False)
    return f"Sent message to user."

def update_message__slack(message, include_user_message: bool = False) -> str:
    print("="*100)
    print(f"[Action] Updating message to user with slack header: {message}")
    print("="*100)

    additional_blocks = []
    latest_user_message_source_provider = (
        get_blocks_runtime_config()
        .get(BlocksRuntimeConfigKeys.LATEST_USER_MESSAGE_SOURCE_PROVIDER, "")
    )

    if include_user_message and latest_user_message_source_provider != BLOCKS_EVENT__PROVIDER.SLACK.value:
        latest_user_message = get_blocks_runtime_config().get(BlocksRuntimeConfigKeys.LATEST_USER_MESSAGE, "")
        latest_user_message = remove_newlines_and_special_characters(latest_user_message)[:500]
        additional_blocks = create_expandable_quote_block(latest_user_message, expand=False)

    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    blocks_runtime_config = get_blocks_runtime_config()
    blocks_comment_ts = blocks_runtime_config.get("metadata", {}).get("blocks_comment_ts")
    channel = blocks_runtime_config.get("metadata", {}).get("slack_channel")

    # Handle both string (markdown) and list (blocks) input
    if isinstance(message, list):
        message_blocks = message
    else:
        _, message_blocks = markdown_to_slack_blocks(message)

    client.chat_update(
        channel=channel, blocks=[
        *additional_blocks,
        *message_blocks
    ], ts=blocks_comment_ts, unfurl_links=False, unfurl_media=False)
    return f"Updated message to user."

def send_message__slack(message: str, urgency_level_between_zero_to_10: int = 5) -> str:

    print("="*100)
    print(f"[Action] Sending message to user with slack directly: {message}")
    print(f"Urgency level: {urgency_level_between_zero_to_10}")
    print("="*100)

    if urgency_level_between_zero_to_10 < THRESHOLD_URGENCY_LEVEL:
        return f"This message is not urgent enough to send to the user. Attempt to continue with the task without user input."

    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    blocks_runtime_config = get_blocks_runtime_config()
    channel = blocks_runtime_config.get("metadata", {}).get("slack_channel")
    ts = blocks_runtime_config.get("metadata", {}).get("slack_ts")

    success, blocks = markdown_to_slack_blocks(message)
    if success:
        client.chat_postMessage(channel=channel, text=message, blocks=blocks, thread_ts=ts, unfurl_links=False, unfurl_media=False)
    else:
        client.chat_postMessage(channel=channel, text=message, thread_ts=ts, unfurl_links=False, unfurl_media=False)
    return f"Sent message to user."


def upload_file__slack(file_path: str, title: str, thread_ts: str, channel_id: str, initial_comment: str = None) -> str:

    print("="*100)
    print(f"[Action] Uploading file to Slack: {file_path}")
    print(f"Title: {title}")
    print(f"Comment: {initial_comment}")
    print("="*100)

    if not os.path.exists(file_path):
        return f"Error: File {file_path} does not exist."

    client = slack_sdk.WebClient(token=SLACK_TOKEN)
    blocks_runtime_config = get_blocks_runtime_config()
    channel = channel_id or blocks_runtime_config.get("metadata", {}).get("slack_channel")
    ts = thread_ts or blocks_runtime_config.get("metadata", {}).get("slack_ts")

    try:
        response = client.files_upload_v2(
            channel=channel,
            file=file_path,
            title=title or os.path.basename(file_path),
            initial_comment=initial_comment,
            thread_ts=ts
        )

        file_url = response['file']['permalink']
        print(f"Upload successful! File URL: {file_url}")
        return f"File uploaded successfully to Slack. URL: {file_url}"

    except Exception as e:
        error_msg = f"Error uploading file to Slack: {str(e)}"
        print(error_msg)
        return error_msg


def download_image_from_slack(file_id: str, output_path: str = None) -> str:
    """
    Download an image from Slack using the file ID.

    Args:
        file_id: The Slack file ID (e.g., F09PUR6LFJL)
        output_path: Optional path where the file should be saved.
                     If not provided, saves to /tmp/{file_id}_{filename}

    Returns:
        str: Success message with the file path, or error message
    """

    print("="*100)
    print(f"[Action] Downloading image from Slack: {file_id}")
    print(f"Output path: {output_path or 'auto-generated'}")
    print("="*100)

    client = slack_sdk.WebClient(token=SLACK_TOKEN)

    try:
        # Get file info
        response = client.files_info(file=file_id)

        if not response['ok']:
            error_msg = f"Error getting file info: {response.get('error', 'Unknown error')}"
            print(error_msg)
            return error_msg

        file_info = response['file']

        # Get the private download URL
        url_private_download = file_info.get('url_private_download')
        if not url_private_download:
            error_msg = "No download URL found for this file"
            print(error_msg)
            return error_msg

        # Determine output path
        if output_path is None:
            filename = file_info.get('name', f'{file_id}.png')
            output_path = f"/tmp/{file_id}_{filename}"

        # Download the file
        import requests
        headers = {
            'Authorization': f'Bearer {SLACK_TOKEN}'
        }

        download_response = requests.get(url_private_download, headers=headers)

        if download_response.status_code != 200:
            error_msg = f"Error downloading file: HTTP {download_response.status_code}"
            print(error_msg)
            return error_msg

        # Save the file
        with open(output_path, 'wb') as f:
            f.write(download_response.content)

        success_msg = f"Image downloaded successfully to: {output_path}"
        print(success_msg)
        print(f"File size: {len(download_response.content)} bytes")
        print(f"File name: {file_info.get('name')}")
        print(f"File type: {file_info.get('mimetype')}")
        return success_msg

    except Exception as e:
        error_msg = f"Error downloading image from Slack: {str(e)}"
        print(error_msg)
        return error_msg
