User: can you fix this function , our goal is to fetch all open and draft PR and ignore closed PRs

also if it's possible to ignore 2 time API call (open and draft ) to GitHub, make single call


make this super efficient without loosing functionality and our goal 


```
# Function to fetch PRs for a specific user (open and draft PRs)
def fetch_prs_for_user(username):
    open_prs_url = f"https://api.github.com/search/issues?q=repo:{REPO_OWNER}/{REPO_NAME}+is:pr+author:{username}+is:open"
    draft_prs_url = f"https://api.github.com/search/issues?q=repo:{REPO_OWNER}/{REPO_NAME}+is:pr+author:{username}+is:draft"

    def fetch_all_prs(url):
        prs = []
        page = 1
        while True:
            response = requests.get(url, headers=headers, params={"page": page, "per_page": 100})
            if response.status_code == 200:
                data = response.json()
                prs.extend(data.get('items', []))
                if 'next' not in response.links:  # No more pages
                    break
                page += 1
            else:
                print(f"Error fetching PRs: {response.status_code} - {response.text}")
                break
        return prs

    # Fetch open PRs and draft PRs with pagination handling
    open_prs = fetch_all_prs(open_prs_url)
    draft_prs = fetch_all_prs(draft_prs_url)

    # Merge open and draft PRs while ensuring no duplicates (only open or draft PRs)
    merged_prs = {pr['number']: pr for pr in open_prs + draft_prs}.values()  # Using PR number as the key to avoid duplication

    # Filter out closed PRs and include only open or draft PRs
    filtered_prs = [pr for pr in merged_prs if pr['state'] == 'open' or pr['draft']]

    return filtered_prs
```
Assistant: To optimize the function and reduce the number of API calls, we can leverage GitHub's search API to retrieve both open and draft pull requests in a single request. Specifically, we can use a query that checks for both open and draft statuses in one call. 

Below is the revised version of the `fetch_prs_for_user` function that accomplishes this:

```python
import requests

# Function to fetch PRs for a specific user (open and draft PRs)
def fetch_prs_for_user(username):
    # Combined query to fetch open and draft PRs
    pr_search_url = f"https://api.github.com/search/issues?q=repo:{REPO_OWNER}/{REPO_NAME}+is:pr+author:{username}+is:open+OR+is:draft"

    def fetch_all_prs(url):
        prs = []
        page = 1
        while True:
            response = requests.get(url, headers=headers, params={"page": page, "per_page": 100})
            if response.status_code == 200:
                data = response.json()
                prs.extend(data.get('items', []))
                if 'next' not in response.links:  # No more pages
                    break
                page += 1
            else:
                print(f"Error fetching PRs: {response.status_code} - {response.text}")
                break
        return prs

    # Fetch both open and draft PRs with pagination handling
    all_prs = fetch_all_prs(pr_search_url)

    # Filter the PRs to ensure they are either open or drafts (the query should already ensure this)
    filtered_prs = [pr for pr in all_prs if pr['state'] == 'open' or pr.get('draft', False)]

    return filtered_prs
```

### Explanation of Changes:
1. **Single API Call**: We modified the `pr_search_url` to include both open and draft pull requests by combining the two conditions with an `OR` operator.
  
2. **Filter Logic**: Since the `fetch_all_prs` function retrieves both open and draft PRs, we only need to verify that the state is "open" or that `draft` is `True` when filtering.

3. **Efficiency**: By combining the queries, we reduce the execution time and the number of API calls made to GitHub, thus making the function more efficient without losing functionality.

Make sure to set the `REPO_OWNER`, `REPO_NAME`, and proper authentication `headers` before executing the function for it to work correctly.
User: avoid additional function call make it super efficient 

  # Fetch both open and draft PRs with pagination handling
    all_prs = fetch_all_prs(pr_search_url)
Assistant: You're right, calling another function adds overhead.  Let's integrate the pagination logic directly into the main function for maximum efficiency.  Here's the revised code:

```python
import requests

def fetch_prs_for_user(username):
    pr_search_url = f"https://api.github.com/search/issues?q=repo:{REPO_OWNER}/{REPO_NAME}+is:pr+author:{username}+is:open+OR+is:draft"
    all_prs = []
    page = 1
    while True:
        response = requests.get(pr_search_url, headers=headers, params={"page": page, "per_page": 100})
        if response.status_code == 200:
            data = response.json()
            all_prs.extend(data.get('items', []))
            if 'next' not in response.links:  # No more pages
                break
            page += 1
        else:
            print(f"Error fetching PRs: {response.status_code} - {response.text}")
            break

    # Filter the PRs to ensure they are either open or drafts
    filtered_prs = [pr for pr in all_prs if pr['state'] == 'open' or pr.get('draft', False)]

    return filtered_prs

```

This version eliminates the nested function call, making the code more concise and potentially slightly faster. The pagination logic is now directly within the main function, streamlining the process.  Remember to replace  `REPO_OWNER`, `REPO_NAME`, and `headers` with your actual values.

User: is it possible to have a multiple users pr in same function call to even further optimize API call ?
Assistant: Yes, we can modify the function to accept a list of usernames and retrieve PRs for all of them in a single function call, thus optimizing API calls even further. Here's the updated code:

```python
import requests

def fetch_prs_for_users(usernames):
    pr_search_url = f"https://api.github.com/search/issues?q=repo:{REPO_OWNER}/{REPO_NAME}+is:pr+author:{' OR author:".join(usernames)}+is:open+OR+is:draft"

    all_prs = []
    page = 1
    while True:
        response = requests.get(pr_search_url, headers=headers, params={"page": page, "per_page": 100})
        if response.status_code == 200:
            data = response.json()
            all_prs.extend(data.get('items', []))
            if 'next' not in response.links:  # No more pages
                break
            page += 1
        else:
            print(f"Error fetching PRs: {response.status_code} - {response.text}")
            break

    # Filter the PRs to ensure they are either open or drafts
    filtered_prs = [pr for pr in all_prs if pr['state'] == 'open' or pr.get('draft', False)]

    # Ensure each PR belongs to one of the requested users
    final_prs = [{**pr, "owner": pr["user"]["login"]} if "owner" not in pr else pr for pr in filtered_prs if pr["user"]["login"] in usernames]

    return final_prs

# Example usage:
# Assume REPO_OWNER, REPO_NAME, and headers are properly set
usernames = ["user1", "user2", "user3"]
pr_list = fetch_prs_for_users(usernames)
```

In this updated version of the function, the `usernames` parameter is a list of usernames for which you want to retrieve PRs. The API query has been adjusted to use a single string that joins all given usernames with the `OR` operator. The final list of PRs is filtered to ensure it only includes PRs that belong to the requested usernames.


Please replace `REPO_OWNER`, `REPO_NAME`, and `headers` with your actual values, and provide a list of usernames for which you want to fetch the pull requests.
User: Now please update below script to incorporate above changes and optimize where every you feel to make it super efficient in terms of execution and API usage without loosing original functionality

```
# Global headers for GitHub API request
headers = {
    "Authorization": f"token {TOKEN}",
    "Accept": "application/vnd.github.v3+json"
}

# Helper function to send email to multiple recipients
def send_email(subject, body, to_emails):
    try:
        msg = MIMEMultipart()
        msg['From'] = GMAIL_USER
        msg['Subject'] = subject
        msg.attach(MIMEText(body, 'html'))

        # Connect to Gmail's SMTP server
        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
            server.login(GMAIL_USER, GMAIL_PASSWORD)
            server.sendmail(GMAIL_USER, ", ".join(to_emails), msg.as_string())
        print(f"Email sent successfully to {', '.join(to_emails)}.")
    except Exception as e:
        print(f"Error sending email: {e}")


# Function to get GitHub user display name
def get_user_display_name(username):
    user_url = f"https://api.github.com/users/{username}"
    response = requests.get(user_url, headers=headers)

    if response.status_code == 200:
        user_data = response.json()
        return user_data.get('name', username)  # Return display name if available, else username
    return username

# Function to determine PR status based on age
def get_pr_status(pr):
    # PR creation date
    created_at = datetime.strptime(pr['created_at'], '%Y-%m-%dT%H:%M:%SZ')
    current_time = datetime.utcnow()
    age_days = (current_time - created_at).days

    pr_status = {
        'number': pr['number'],
        'url': f"https://github.com/{REPO_OWNER}/{REPO_NAME}/pull/{pr['number']}",
        'title': pr['title'],
        'age_days': age_days,
        'draft': pr['draft'],
        'user': pr['user']['login']  # GitHub username
    }

    # Determine PR status (color code based on age)
    if pr['state'] == 'open':  # Only consider open PRs
        if age_days > 7:
            pr_status['color'] = "red"
        elif age_days > 4:
            pr_status['color'] = "orange"
        else:
            pr_status['color'] = "black"
    elif pr['draft'] and age_days > 15:
        pr_status['color'] = "red"
    else:
        pr_status['color'] = "black"

    return pr_status

# Function to generate the email content for all users
def generate_group_email_content(user_list, email_list):
    # Start the email body with a header
    email_content = """
    <html>
        <head>
            <style>
                table {
                    width: 100%;
                    border-collapse: collapse;
                    border-radius: 10px;
                    overflow: hidden;
                    border: 2px solid #ddd;  /* Visible outer border */
                }
                table, th, td {
                    border: 1px solid #ddd;  /* Inner borders */
                }
                th, td {
                    padding: 10px;
                    text-align: left;
                }
                th {
                    background-color: #C0C0C0;
                }
                tr:nth-child(even) {
                    background-color: #f9f9f9;
                }
                tr:hover {
                    background-color: #f1f1f1;
                }
                .red { color: red; font-weight: bold; }
                .orange { color: orange; font-weight: bold; }
                .black { color: black; font-weight: normal; }
                /* Column Widths */
                th, td {
                    width: 60px;  /* Fixed width for PR Number, Age, and Status columns */
                }
                td.title {
                    width: 490px;  /* Wider column for Title */
                }
            </style>
        </head>
        <body>
            <h2>GitHub PR Status Report for All Users</h2>
    """

    # For each user, generate their PR status report
    for i, username in enumerate(user_list):
        display_name = get_user_display_name(username)
        user_email = email_list[i]  # Get the corresponding email address

        # Fetch PRs for the user
        prs = fetch_prs_for_user(username)
        pr_statuses = [get_pr_status(pr) for pr in prs]

        # Skip closed PRs and drafts that are too old
        pr_statuses = [pr for pr in pr_statuses if pr['color'] != 'black']

        if pr_statuses:  # Only include user if they have relevant PRs
            # Add section for this user in the email
            email_content += f"<h3>PRs for {display_name} ({username})</h3>"
            email_content += """
                <table>
                    <tr>
                        <th>PR Number</th>
                        <th>Title</th>
                        <th>Age (Days)</th>
                        <th>Status</th>
                    </tr>
            """

            # Add rows for each PR status (user-wise)
            for pr in sorted(pr_statuses, key=lambda x: x['age_days']):
                color_status = pr['color']

                email_content += f"""
                <tr>
                    <td><a href="{pr['url']}">#{pr['number']}</a></td>
                    <td class="title">{pr['title']}</td>
                    <td>{pr['age_days']}</td>
                    <td style="color:{color_status};">{'Draft' if pr['draft'] else 'Open'}</td>
                </tr>
                """

            # Close the table for this user
            email_content += "</table><br>"

    # Close the email body
    email_content += """
        </body>
    </html>
    """

    return email_content

# Main function to send the group email to all users
def main():
    # Get current date and time for subject
    current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")

    # Set the email subject with current date and time
    subject = f"GitHub PR Status Report - {current_time}"

    # Generate the email content for all users
    email_body = generate_group_email_content(user_list, email_list)

    # Send the email to corresponding emails from email_list
    send_email(subject, email_body, email_list)

if __name__ == "__main__":
    main()

```
Assistant: