import json
import os
from datetime import datetime
import string
import requests
from .test_results_to_jira import load_third_party_config


def send_slack_message(slack_webhook_url, message_blocks):
    payload = {"blocks": message_blocks}
    response = requests.post(slack_webhook_url, data=json.dumps(
        payload), headers={'Content-Type': 'application/json'}, timeout=30)
    if response.status_code != 200:
        raise ValueError(
            f"Request to Slack returned an error {response.status_code}, the response is:\n{response.text}")
    print("Slack notification sent!")


def generate_ai_summary(report) -> str:
    """
    Generate an AI-powered summary of test results using OpenAI API.

    Args:
        report: Test report dictionary
        test_run: Test run name
        test_env: Test environment

    Returns:
        AI-generated summary string
    """
    # OpenAI API endpoint
    openai_api_url = "https://api.openai.com/v1/chat/completions"

    # Get OpenAI API key from environment
    openai_api_key = os.environ.get('OPENAI_API_KEY')
    if not openai_api_key:
        return "AI summary unavailable: OPENAI_API_KEY not set"

    # Prepare test report summary for AI
    all_tests = report['tests']

    # Create test details for AI analysis
    test_details = []
    for test in all_tests:
        nodeid = test['nodeid'].replace('[', '-').replace(']', '')
        test_name = nodeid.split(
            '::')[-1].replace('test_', '', 1).replace('_', ' ').replace('validate', '').capitalize().strip()
        # Truncate error details to avoid payload size issues
        error_details = test.get('call', {}).get('longrepr', '') if test['outcome'] in [
            'failed', 'error'] else ''
        if error_details and len(error_details) > 1000:
            error_details = error_details[:1000] + "... (truncated)"

        test_info = {
            'test': test_name,
            'outcome': test['outcome'],
            'duration': round(test.get('duration', 0), 2),
            'keywords': test.get('keywords', []),
            'error_details': error_details,
            'more_info': next((prop.get('more_info') for prop in test.get('user_properties', []) if 'more_info' in prop), '')
        }
        test_details.append(test_info)

    # Create a detailed prompt for AI
    prompt = f"""You are analyzing test results. Generate a test-by-test report showing test definitions and failure analysis.

All Tests Data:
{json.dumps(test_details, indent=2)}

REQUIRED OUTPUT FORMAT for EACH TEST:

1. Failed: No alerts failed today
    - RCA: <AI-analyzed root cause from error_details, strictly under 150 words. When error_details contain specific Case IDs and Reasons/Resolutions, include 3 most diverse or recent examples, each on a new line prefixed with "-- " in format: "-- Case ID: <id> - Resolution: <reason>">

2. Passed: Alerts processed successfully today
    - More Info: <AI-translated information from more_info in max 100 words> (only include this line if more_info is not empty)

INSTRUCTIONS:
- List all failed tests first, followed by passed tests
- For passed tests only show the "More Info" line if more_info field has content
- DEDUPLICATION: Group similar RCA reasons by context (e.g., WAF-related, scanning-related, false positives) and consolidate into 1-2 representative reasons
- RCA CONTENT: Skip generic phrases like "The test failed due to an assertion error" - focus ONLY on the specific business reason (what actually failed, expected vs actual values, context from error messages)
- Output only the numbered test analysis in the exact format above - no additional commentary, introductions, or conclusions

Generate the numbered list now:"""

    # Prepare the request
    headers = {
        "Authorization": f"Bearer {openai_api_key}",
        "Content-Type": "application/json"
    }

    payload = {
        "messages": [
            {
                "role": "system",
                "content": "You are an Expirienced Quality Engineering generating concise test result summaries. Follow the exact format provided in the prompt."
            },
            {
                "role": "user",
                "content": prompt
            }
        ],
        "model": "gpt-4",
        "temperature": 0.5,
        "max_tokens": 2000
    }

    try:
        response = requests.post(
            openai_api_url,
            headers=headers,
            json=payload,
            timeout=30
        )

        if response.status_code == 200:
            result = response.json()
            ai_summary = result['choices'][0]['message']['content']
            return ai_summary
        elif response.status_code == 400:
            print(f"OpenAI API 400 Bad Request - Invalid payload or token issue")
            print(f"Response: {response.text}")
        else:
            print(
                f"OpenAI API error: {response.status_code} - {response.text}")
            return f"AI summary unavailable: API returned status {response.status_code}"
    except Exception as e:
        print(f"Error calling OpenAI API: {str(e)}")
        return f"AI summary unavailable: {str(e)}"


def send_slack_notification(report, test_run, test_env, test_run_id, slack_message_type="regular") -> None:
    third_party_config = load_third_party_config()
    test_type = report['tests'][0]['nodeid'].split('/')[0]
    build_url = f"{os.environ.get(third_party_config['scm_url_variable'])}/pipelines/results/{os.environ.get(third_party_config['scm_build_number_variable'])}" if os.environ.get(
        third_party_config['scm_url_variable']) else "Not Applicable"
    failed_tests_count_high = len([test for test in report['tests'] if (
        test['outcome'] == 'failed' or test['outcome'] == 'error') and 'high' in test.get('keywords', [])])
    failed_tests_count_med = len([test for test in report['tests'] if (
        test['outcome'] == 'failed' or test['outcome'] == 'error') and 'medium' in test.get('keywords', [])])
    failed_tests_count_low = len([test for test in report['tests'] if (
        test['outcome'] == 'failed' or test['outcome'] == 'error') and 'low' in test.get('keywords', [])])
    failed_tests_count_total = len(
        [test for test in report['tests'] if test['outcome'] == 'failed' or test['outcome'] == 'error'])
    skipped_tests_count = len(
        [test for test in report['tests'] if test['outcome'] == 'skipped'])
    eligible_test_count_total = len(report['tests']) - skipped_tests_count
    reliability_percentage = round(((eligible_test_count_total - failed_tests_count_total) /
                                   eligible_test_count_total) * 100, 2) if eligible_test_count_total > 0 else 0.0
    failed_skipped_report_url = f"{os.environ.get('jira_host_url')}/issues/?jql=project%20%3D%20{os.environ.get('jira_project_key')}%20AND%20%22trid%5BShort%20text%5D%22%20~%20%22{test_run_id}%22%20AND%20%22test%20status%5BDropdown%5D%22%20IN%20(Failed%2C%20Skipped)%20ORDER%20BY%20status%20ASC"
    failed_high_report_url = f"{os.environ.get('jira_host_url')}/issues/?jql=project%20%3D%20{os.environ.get('jira_project_key')}%20AND%20%22trid%5BShort%20text%5D%22%20~%20%22{test_run_id}%22%20AND%20%22test%20status%5BDropdown%5D%22%20IN%20(Failed)%20AND%20%22Test%20Tags%5BLabels%5D%22%20IN%20(high)%20ORDER%20BY%20status%20ASC"
    failed_medium_report_url = f"{os.environ.get('jira_host_url')}/issues/?jql=project%20%3D%20{os.environ.get('jira_project_key')}%20AND%20%22trid%5BShort%20text%5D%22%20~%20%22{test_run_id}%22%20AND%20%22test%20status%5BDropdown%5D%22%20IN%20(Failed)%20AND%20%22Test%20Tags%5BLabels%5D%22%20IN%20(medium)%20ORDER%20BY%20status%20ASC"
    failed_low_report_url = f"{os.environ.get('jira_host_url')}/issues/?jql=project%20%3D%20{os.environ.get('jira_project_key')}%20AND%20%22trid%5BShort%20text%5D%22%20~%20%22{test_run_id}%22%20AND%20%22test%20status%5BDropdown%5D%22%20IN%20(Failed)%20AND%20%22Test%20Tags%5BLabels%5D%22%20IN%20(low)%20ORDER%20BY%20status%20ASC"

    # print(
    #     f"📊 *Split:* 🔴 High: <{failed_high_report_url}|{failed_tests_count_high}> 🟡 Medium: <{failed_medium_report_url}|{failed_tests_count_med}> 🟢 Low: <{failed_low_report_url}|{failed_tests_count_low}> ⚫ Skipped: {skipped_tests_count}\n")

    # Generate AI summary if descriptive mode is enabled
    if slack_message_type == "detailed":
        ai_summary = generate_ai_summary(report)
        blocks = [
            {
                "type": "header",
                "text": {
                    "type": "plain_text",
                    "text": f"AI Agent Reliability Test Results - {test_env}",
                    "emoji": True
                }
            },
            {
                "type": "divider"
            },
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"{ai_summary}"
                }
            },
            {
                "type": "divider"
            },
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"- Current reliability is {reliability_percentage} (%)\n- Click to view <{failed_skipped_report_url}|Failed/Skipped> tests in Jira"
                }
            },
            {
                "type": "context",
                "elements": [
                    {
                        "type": "mrkdwn",
                        "text": f"Execution Date: _{datetime.fromtimestamp(report.get('created', 0)).strftime('%b-%d-%Y at %H:%M')}_\n_*Generated with Quality AIngineering - ΣβΔΨ*_"
                    }
                ]
            }
        ]
    else:
        blocks = [
            {
                "type": "header",
                "text": {
                    "type": "plain_text",
                    "text": f"{string.capwords(test_type.replace('_', ' '))} Results",
                    "emoji": True
                }
            },
            {
                "type": "divider"
            },
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"🚀 *Test Run:* {test_run}\n"
                        f"🌎 *Environment:* {test_env}\n"
                        f"❌ *Failed:* {report.get('summary', {}).get('failed', 0)}\n"
                        f"📊 *Split:* 🔴 High: <{failed_high_report_url}|{failed_tests_count_high}> 🟡 Medium: <{failed_medium_report_url}|{failed_tests_count_med}> 🟢 Low: <{failed_low_report_url}|{failed_tests_count_low}> ⚫ Skipped: {skipped_tests_count}\n"
                        f"📈 Click to open <{failed_skipped_report_url}|Failed/Skipped Tests> in Jira\n"
                }
            },
            {
                "type": "divider"
            },
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"🧪 *Total Tests:* {report.get('summary', {}).get('total', 0)}\n"
                        f"✅ *Passed:* {report.get('summary', {}).get('passed', 0)}\n"
                        f"🔄 *Executed:* {report.get('summary', {}).get('collected', 0)}\n"
                        f"⏸️ *Skipped:* {report.get('summary', {}).get('deselected', 0)}\n"
                        f"🛠️ Click to open <{build_url}|Build {os.environ.get('BITBUCKET_BUILD_NUMBER', '-')}>\n"
                }
            },
            {
                "type": "context",
                "elements": [
                    {
                        "type": "mrkdwn",
                        "text": f"Execution Date: _{datetime.fromtimestamp(report.get('created', 0)).strftime('%b-%d-%Y')}_"
                    }
                ]
            }
        ]

    slack_webhook_url = os.environ.get('slack_test_webhook') if test_run != 'Daily Run' else os.environ.get(
        'slack_dev_channel_webhook') if test_env.lower() == 'dev' else os.environ.get('slack_prod_channel_webhook')
    send_slack_message(slack_webhook_url=slack_webhook_url,
                       message_blocks=blocks)
