import os
import json
import uuid
import requests
from typing import Optional
from blocks import config, 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.tools.blocks import get_task_header, send_message__blocks

def get_new_github_token():
    blocks_runtime_config = get_blocks_runtime_config()
    return blocks_runtime_config.get("GITHUB_TOKEN", os.getenv("GITHUB_TOKEN"))

def download_images_from_github_comment_id(
    owner: str,
    repo: str,
    comment_id: str,
    save_dir: Optional[str] = None
) -> str:
    """
    Download all images from a GitHub issue/PR comment by fetching the comment's HTML
    representation through the GitHub API, which automatically converts user-attachment
    URLs to temporary signed URLs.

    Args:
        owner: Repository owner (e.g., "BlocksOrg")
        repo: Repository name (e.g., "agents")
        comment_id: The comment ID (not the issue/PR number)
        save_dir: Optional directory to save images. If not provided, saves to /tmp

    Returns:
        Success message with list of downloaded file paths, or error message
    """
    print("="*100)
    print(f"TOOL CALL: Downloading GitHub images from comment {comment_id}")
    print("="*100)

    try:
        github_token = get_new_github_token()
        if not github_token:
            error_msg = "Error: GITHUB_TOKEN not available"
            print(error_msg)
            return error_msg

        # Step 1: Fetch the comment with HTML representation
        print(f"Step 1: Fetching comment from {owner}/{repo}...")

        response = requests.get(
            f"https://api.github.com/repos/{owner}/{repo}/issues/comments/{comment_id}",
            headers={
                "Authorization": f"Bearer {github_token}",
                "Accept": "application/vnd.github.html+json",
                "User-Agent": "Blocks-Agent/1.0"
            },
            timeout=30
        )

        if response.status_code != 200:
            error_msg = f"Error fetching comment: HTTP {response.status_code} - {response.text}"
            print(error_msg)
            return error_msg

        comment_data = response.json()
        body_html = comment_data.get("body_html", "")
        print(f"Successfully fetched comment (HTML length: {len(body_html)})")

        # Step 2: Extract all private-user-images URLs from the HTML
        print("Step 2: Extracting image URLs from HTML...")

        import re
        pattern = r'src="(https://private-user-images\.githubusercontent\.com[^"]*)"'
        signed_urls = re.findall(pattern, body_html)

        if not signed_urls:
            error_msg = "No images found in comment"
            print(error_msg)
            return error_msg

        print(f"Found {len(signed_urls)} image(s)")

        # Step 3: Download all images
        print("Step 3: Downloading images...")

        downloaded_files = []
        save_dir = save_dir or "/tmp"

        for i, signed_url in enumerate(signed_urls):
            print(f"\nDownloading image {i+1}/{len(signed_urls)}...")

            download_response = requests.get(
                signed_url,
                headers={
                    "Authorization": f"Bearer {github_token}",
                    "User-Agent": "Blocks-Agent/1.0"
                },
                timeout=30
            )

            if download_response.status_code != 200:
                print(f"Warning: Failed to download image {i+1}: HTTP {download_response.status_code}")
                continue

            # Determine file extension from content type
            extension = "jpg"  # default
            content_type = download_response.headers.get('Content-Type', '').lower()
            if 'png' in content_type:
                extension = "png"
            elif 'jpeg' in content_type or 'jpg' in content_type:
                extension = "jpg"
            elif 'gif' in content_type:
                extension = "gif"
            elif 'webp' in content_type:
                extension = "webp"

            filename = f"github_comment_{comment_id}_image_{i+1}.{extension}"
            save_path = os.path.join(save_dir, filename)

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

            downloaded_files.append(save_path)
            print(f"✓ Saved: {save_path} ({len(download_response.content)} bytes)")

        if not downloaded_files:
            error_msg = "Failed to download any images"
            print(error_msg)
            return error_msg

        success_msg = f"Successfully downloaded {len(downloaded_files)} image(s):\n" + "\n".join(downloaded_files)
        print("\n" + "="*100)
        print(success_msg)
        print("="*100)

        return success_msg

    except requests.exceptions.RequestException as e:
        error_msg = f"Error downloading images from GitHub: {str(e)}"
        print(error_msg)
        return error_msg
    except IOError as e:
        error_msg = f"Error saving GitHub images to disk: {str(e)}"
        print(error_msg)
        return error_msg
    except Exception as e:
        error_msg = f"Unexpected error downloading GitHub images: {str(e)}"
        print(error_msg)
        return error_msg

def get_code_repositories_block() -> str:
    GITHUB_REPOSITORIES = os.getenv("GITHUB_REPOSITORIES", "[]")

    has_any_repos = False

    contents = "<code_repositories>\n\n"
    try:
        is_array = isinstance(GITHUB_REPOSITORIES, list)
        if is_array:
            repositories = GITHUB_REPOSITORIES
        else:
            repositories = json.loads(GITHUB_REPOSITORIES)
        has_any_repos = len(repositories) > 0
        for repository in repositories:
            contents += f"  <full_name>{repository}</full_name>\n\n"
    except Exception as e:
        print("Unable to fetch Github repositories.")
    
    contents += "</code_repositories>\n\n"
    return contents if has_any_repos else ""

def get_code_repositories_with_additional_info_block() -> str:
    """
    Get the github repositories with additional info block.
    """
    BLOCKS_AVAILABLE_REPOSITORIES = os.getenv("BLOCKS_AVAILABLE_REPOSITORIES", "[]")

    try:
        available_repositories = json.loads(BLOCKS_AVAILABLE_REPOSITORIES)

        has_any_repos = len(available_repositories) > 0

        if not has_any_repos:
            return ""

    except Exception as e:
        print(f"Error parsing BLOCKS_AVAILABLE_REPOSITORIES: {e}")
        return ""

    contents = "<code_repositories>\n"
    for repository in available_repositories:
        contents += f"<repository>\n"
        contents += f"  <url>{repository.get('url')}</url>\n"
        contents += f"  <external_id>{repository.get('external_id')}</external_id>\n"
        contents += f"  <default_branch>{repository.get('default_branch')}</default_branch>\n"
        contents += f"  <last_activity>{repository.get('last_activity')}</last_activity>\n"
        contents += f"</repository>\n"
    contents += "</code_repositories>\n"

    return contents

def update_github_issue_or_pr_comment_with_header(comment_id: str, body: str = ""):
    """
    Update the comment.
    """
    print("="*100)
    print(f"TOOL CALL: Updating github issue or pr comment with header: {comment_id}")
    print("="*100)

    issue_body_header = get_task_header(is_github=True)
    if body:
        # strip newlines
        body = remove_newlines_and_special_characters(body)
        issue_body_header += f"\n> {body}"
    res = repo.update_issue_comment(comment_id, issue_body_header)
    return res.get("id")

def update_github_pr_comment_on_file_with_header(comment_id: str, body: str = ""):
    """
    Update the pull request comment on file.
    """
    print("="*100)
    print(f"TOOL CALL: Updating github issue or pr comment with header: {comment_id}")
    print("="*100)

    issue_body_header = get_task_header(is_github=True)
    if body:
        # strip newlines
        body = remove_newlines_and_special_characters(body)
        issue_body_header += f"\n> {body}"
    res = repo.update_pull_request_comment(comment_id, issue_body_header)
    return res.get("id")

def todo_list_update__github_issue_or_pr(body: str, current_task: str, in_progress: bool = True) -> str:
    """
    Update the todo list.
    """
    print("="*100)
    print(f"TOOL CALL: Updating todo list")
    print("="*100)
    blocks_runtime_config = get_blocks_runtime_config()
    comment_id = blocks_runtime_config.get("metadata", {}).get("comment_id")
    llm_provider_str = blocks_runtime_config.get("llm_provider")
    original_body = body

    patch_blocks_runtime_config({
       BlocksRuntimeConfigKeys.LATEST_TODO_LIST: body
    })

    IN_PROGRESS_GIF = '<img src="https://github.com/user-attachments/assets/5ac382c7-e004-429b-8e35-7feb3e8f9c6f" width="14px" height="14px" style="vertical-align:middle;margin-left:4px;">'
    body = f"## Blocks - Delegated to `{llm_provider_str}` Agent {IN_PROGRESS_GIF if in_progress else ''}\n{original_body}"
    if not in_progress:
        body += "\n\n> Preparing summary for your review..."
    if comment_id:
        repo.update_issue_comment(comment_id, body)
    else:
        print("No comment id found in blocks runtime config")
    return f"Updated todo list: {body}"

def create_github_issue_comment(issue_id: str, body: str):
    res = repo.comment_on_issue(
        issue_number=issue_id, 
        body=body
    )
    id = res.get("id")
    return id

def create_github_pr_comment(pr_id: str, body: str):
    res = repo.comment_on_pull_request(
        pull_request_number=pr_id, 
        body=body
    )
    id = res.get("id")
    return id

def create_github_pr_respond_to_comment_on_file(body: str, pull_request_number: str, reply_to_id: str):
    res = repo.reply_to_pull_request_comment(
        reply_to_id=reply_to_id,
        pull_request_number=pull_request_number,
        body=body
    )
    id = res.get("id")
    return id

def update_github_pr_respond_to_comment_on_file(comment_id: str, body: str):
    res = repo.update_pull_request_comment(
        comment_id=comment_id,
        body=body
    )
    id = res.get("id")
    return id

def update_message__github(message: str, include_user_message: bool = False):
    """
    Update GitHub issue/PR comment with the final message, optionally including user message block.
    Similar to update_message__slack() but adapted for GitHub markdown.

    Args:
        message: The final message to update (markdown string with footer)
        include_user_message: Whether to include the user message as a quoted block
    """
    print("="*100)
    print(f"TOOL CALL: Updating GitHub message with footer")
    print(f"Include user message: {include_user_message}")
    print("="*100)

    blocks_runtime_config = get_blocks_runtime_config()
    comment_id = blocks_runtime_config.get("metadata", {}).get("comment_id")

    if not comment_id:
        print("No comment id found in blocks runtime config")
        return

    # Get the latest user message source provider to check if we should include it
    from blocks_control_sdk.blocks_events.context import BLOCKS_EVENT__PROVIDER
    latest_user_message_source_provider = blocks_runtime_config.get(
        BlocksRuntimeConfigKeys.LATEST_USER_MESSAGE_SOURCE_PROVIDER
    )

    final_message = message

    # If include_user_message is True AND the message did NOT originate from GitHub
    # Then prepend the user message as a quoted block (similar to Slack behavior)
    if include_user_message and latest_user_message_source_provider != BLOCKS_EVENT__PROVIDER.GITHUB.value:
        latest_user_message = blocks_runtime_config.get(BlocksRuntimeConfigKeys.LATEST_USER_MESSAGE, "")

        if latest_user_message:
            # Truncate and clean the user message
            latest_user_message = remove_newlines_and_special_characters(latest_user_message)[:500]

            # Format as GitHub markdown blockquote
            user_message_block = f"**User Message:**\n> {latest_user_message}\n\n"
            final_message = user_message_block + message

    # Update the comment
    from blocks_control_sdk.blocks_events.context import BLOCKS_EVENT__TRIGGER_ALIAS
    blocks_trigger_alias = os.getenv("BLOCKS_TRIGGER_ALIAS")

    if blocks_trigger_alias == BLOCKS_EVENT__TRIGGER_ALIAS.GITHUB_PULL_REQUEST_REVIEW_COMMENT.value:
        repo.update_pull_request_comment(comment_id, final_message)
    else:
        repo.update_issue_comment(comment_id, final_message)

    print(f"Successfully updated GitHub comment {comment_id}")
    return comment_id