"""
Botify Code Generation System

This module centralizes all Botify Python code generation utilities,
eliminating ~400+ lines of duplicated code across plugins.

Used by Parameter Buster, Link Graph Visualizer, and other Botify workflows
for consistent Python debugging code generation.
"""

import json
from typing import Dict, Any, Optional, List
from pathlib import Path


def get_ui_constants():
    """Get UI constants for code formatting."""
    return {
        'CODE_FORMATTING': {
            'COMMENT_DIVIDER': '#' * 80
        }
    }


def generate_botify_code_header(
    display_name: str, 
    step_name: str, 
    username: str, 
    project_name: str,
    template_info: dict = None, 
    qualifier_config: dict = None
) -> List[str]:
    """Generate standardized header for Botify Python debugging code.
    
    Centralizes the header generation logic to reduce duplication across plugins.
    """
    ui_constants = get_ui_constants()
    comment_divider = ui_constants['CODE_FORMATTING']['COMMENT_DIVIDER']
    
    header_lines = [
        comment_divider,
        f"# Botify API Call Example",
        f"# Generated by: {display_name}",
        f"# Step: {step_name}",
        f"# Organization: {username}",
        f"# Project: {project_name}"
    ]
    
    # Add template information if provided
    if template_info:
        header_lines.append("#")
        header_lines.append(f"# Query Template: {template_info.get('name', 'Unknown')}")
        header_lines.append(f"# Description: {template_info.get('description', 'No description available')}")
        header_lines.append(f"# Export Type: {template_info.get('export_type', 'Unknown')}")
        
        # Add qualifier information if present
        if qualifier_config and qualifier_config.get('enabled', False):
            header_lines.append("#")
            header_lines.append("# 🎯 SMART QUALIFIER SYSTEM:")
            header_lines.append(f"# This template uses automatic parameter optimization to stay under API limits.")
            param_name = qualifier_config.get('iterative_parameter_name', 'parameter')
            max_threshold = qualifier_config.get('max_value_threshold', 1000000)
            header_lines.append(f"# The system automatically finds the optimal {param_name} for ~{max_threshold:,} results.")
            if 'user_message_found' in qualifier_config:
                msg_template = qualifier_config['user_message_found']
                if '{param_value}' in msg_template and '{metric_value}' in msg_template:
                    header_lines.append(f"# Example: 'Optimal {param_name}: 2 (for 235,623 results)'")
    
    header_lines.extend([
        "#",
        "# 🧪 For live JupyterLab environment to experiment with queries:",
        "# http://localhost:8888/lab/tree/helpers/botify/botify_api.ipynb",
        "#",
        "# 📋 For copy/paste-able examples to use in JupyterLab:",
        "# http://localhost:5001/documentation",
        comment_divider
    ])
    
    return header_lines


def generate_botify_token_loader() -> str:
    """Generate the standard Botify token loading function."""
    return '''def load_api_token() -> str:
    """Load the Botify API token from the token file."""
    try:
        if not os.path.exists(TOKEN_FILE):
            raise ValueError(f"Token file '{TOKEN_FILE}' not found.")
        with open(TOKEN_FILE) as f:
            content = f.read().strip()
            api_key = content.split('\\n')[0].strip()
            if not api_key:
                raise ValueError(f"Token file '{TOKEN_FILE}' is empty.")
            return api_key
    except Exception as e:
        raise ValueError(f"Error loading API token: {str(e)}")'''


def generate_botify_http_client(client_name: str, description: str) -> str:
    """Generate the standard HTTP client function for Botify APIs."""
    return f'''async def {client_name}(
    url: str,
    headers: Dict[str, str],
    payload: Dict[str, Any],
    timeout: float = 60.0
) -> Dict[str, Any]:
    """
    {description}

    Args:
        url: The API endpoint URL
        headers: Request headers
        payload: Request payload
        timeout: Request timeout in seconds

    Returns:
        Dict containing the API response data

    Raises:
        ValueError: If the API call fails or returns an error
    """
    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                url=url,
                headers=headers,
                json=payload,
                timeout=timeout
            )

            print(f"Status Code: {{response.status_code}}")
            response.raise_for_status()

            result = response.json()
            print(f"\\nResults returned: {{len(result.get('results', []))}}")
            print(f"Total count: {{result.get('count', 'N/A')}}")

            # Show first few results for inspection
            results = result.get('results', [])
            if results:
                print("\\nFirst result structure:")
                print(json.dumps(results[0], indent=2))

            return result

        except httpx.HTTPStatusError as e:
            error_msg = f"HTTP error {{e.response.status_code}}: {{e.response.text}}"
            print(f"\\n❌ Error: {{error_msg}}")
            raise ValueError(error_msg)
        except Exception as e:
            error_msg = f"Unexpected error: {{str(e)}}"
            print(f"\\n❌ Error: {{error_msg}}")
            raise ValueError(error_msg)'''


def generate_botify_main_executor(client_function_name: str, api_description: str) -> str:
    """Generate the main execution function for Botify APIs."""
    return f'''async def main():
    """Main execution function for {api_description}"""
    try:
        result = await {client_function_name}(
            url=URL,
            headers=get_headers(),
            payload=PAYLOAD
        )
        return result

    except Exception as e:
        print(f"\\n❌ {api_description} failed: {{str(e)}}")
        raise

# Execute in Jupyter Notebook:
await main()

# For standalone script execution:
# if __name__ == "__main__":
#     import asyncio
#     asyncio.run(main())'''


def generate_botify_bqlv2_python_code(
    query_payload,
    username,
    project_name,
    page_size,
    jobs_payload,
    display_name,
    get_step_name_from_payload_func,
    get_configured_template_func=None,
    query_templates=None
):
    """
    🚀 REUSABLE UTILITY: Generate complete Python code for BQLv2 queries (crawl, GSC)
    
    This eliminates ~100+ lines of duplicated f-string blocks across Botify plugins.
    Used by Trifecta, Parameter Buster, Link Graph for consistent code generation.
    """
    # Build the query URL with pagination parameter
    query_url = f"https://api.botify.com/v1/projects/{username}/{project_name}/query?size={page_size}"
    
    # Convert Python objects to proper JSON representation
    payload_json = json.dumps(query_payload, indent=4)
    payload_json = payload_json.replace(': false', ': False').replace(': true', ': True').replace(': null', ': None')
    
    # Extract template information if functions provided
    template_info = None
    qualifier_config = None
    if get_configured_template_func and query_templates:
        try:
            # Try different template config keys that plugins use
            for template_key in ['analysis', 'crawl']:
                try:
                    configured_template = get_configured_template_func(template_key)
                    template_info = query_templates.get(configured_template, {})
                    if template_info:
                        qualifier_config = template_info.get('qualifier_config', {})
                        break
                except (AttributeError, KeyError):
                    continue
        except Exception:
            pass
    
    # Generate header using reusable utility
    step_name = get_step_name_from_payload_func(jobs_payload)
    header_lines = generate_botify_code_header(
        display_name=f"{display_name} Workflow",
        step_name=f"{step_name} (BQLv2 - for debugging the export query)",
        username=username,
        project_name=project_name,
        template_info=template_info,
        qualifier_config=qualifier_config
    )
    header_comment = "\n".join(header_lines)
    
    # Generate Python code using reusable utilities
    token_loader = generate_botify_token_loader()
    http_client = generate_botify_http_client(
        client_name="make_query_call",
        description="Make a BQLv2 query API call to debug the export query structure."
    )
    main_executor = generate_botify_main_executor(
        client_function_name="make_query_call",
        api_description="BQLv2 query debugging"
    )
    
    python_code = f'''{header_comment}

import httpx
import json
import os
from typing import Dict, Any

# Configuration
TOKEN_FILE = 'botify_token.txt'

{token_loader}

# Configuration  
API_TOKEN = load_api_token()
URL = "{query_url}"

# Headers setup
def get_headers() -> Dict[str, str]:
    """Generate headers for the API request."""
    return {{
        'Authorization': f'Token {{API_TOKEN}}',
        'Content-Type': 'application/json'
    }}

# Query payload (converted from export job)
PAYLOAD = {payload_json}

{http_client}

{main_executor}
'''
    
    return query_url, query_payload, python_code


def generate_botify_bqlv1_python_code(
    query_payload,
    username,
    project_name,
    jobs_payload,
    display_name,
    get_step_name_from_payload_func
):
    """
    🚀 REUSABLE UTILITY: Generate complete Python code for BQLv1 queries (web logs)
    
    This eliminates ~150+ lines of duplicated f-string blocks across Botify plugins.
    Used by Trifecta, Parameter Buster, Link Graph for web logs API calls.
    """
    # Extract the web logs specific data
    start_date = query_payload.get("start_date", "")
    end_date = query_payload.get("end_date", "")
    query_body = query_payload.get("query_body", {})
    
    # Convert to proper JSON representation
    query_body_json = json.dumps(query_body, indent=4)
    query_body_json = query_body_json.replace(': false', ': False').replace(': true', ': True').replace(': null', ': None')
    
    # CRITICAL: Web logs API uses app.botify.com/api NOT api.botify.com like other endpoints!
    logs_url = f"https://app.botify.com/api/v1/logs/{username}/{project_name}/urls/{start_date}/{end_date}"
    
    # Generate header with web logs-specific template info
    weblog_template_info = {
        'name': 'Web Logs (Hardcoded - KISS Principle)',
        'description': 'Simple web logs query with consistent fields and filters',
        'export_type': 'weblog'
    }
    
    step_name = get_step_name_from_payload_func(jobs_payload)
    header_lines = generate_botify_code_header(
        display_name=f"{display_name} Workflow",
        step_name=f"{step_name} (BQLv1 - /logs endpoint) | Date Range: {start_date} to {end_date}",
        username=username,
        project_name=project_name,
        template_info=weblog_template_info,
        qualifier_config=None
    )
    
    # Insert web logs-specific notes
    insert_index = -4
    weblog_notes = [
        "#",
        "# 📝 NOTE: Web logs are intentionally NOT templated for simplicity:",
        "# - Always same fields: ['url', 'crawls.google.count']",
        "# - Always same filter: crawls.google.count > 0", 
        "# - Uses legacy BQLv1 structure (different from crawl/GSC)",
        "# - Different API endpoint (app.botify.com vs api.botify.com)"
    ]
    
    for i, note in enumerate(weblog_notes):
        header_lines.insert(insert_index + i, note)
        
    header_comment = "\n".join(header_lines)
    token_loader = generate_botify_token_loader()
    
    python_code = f'''{header_comment}

import httpx
import json
import os
from typing import Dict, Any

# Configuration
TOKEN_FILE = 'botify_token.txt'

{token_loader}

# Configuration
API_TOKEN = load_api_token()
BASE_URL = "{logs_url}"

# Headers setup
def get_headers() -> Dict[str, str]:
    """Generate headers for the API request."""
    return {{
        'Authorization': f'Token {{API_TOKEN}}',
        'Content-Type': 'application/json'
    }}

# Web Logs Query Payload (BQLv1 format)
QUERY_PAYLOAD = {query_body_json}

async def make_web_logs_call(
    base_url: str,
    headers: Dict[str, str],
    payload: Dict[str, Any],
    page: int = 1,
    size: int = 50,
    sampling: int = 100,
    timeout: float = 60.0
) -> Dict[str, Any]:
    """Make a BQLv1 web logs API call to debug the export query structure."""
    async with httpx.AsyncClient() as client:
        try:
            url_with_params = f"{{base_url}}?page={{page}}&size={{size}}&sampling={{sampling}}"
            response = await client.post(url=url_with_params, headers=headers, json=payload, timeout=timeout)
            print(f"Status Code: {{response.status_code}}")
            response.raise_for_status()
            result = response.json()
            print(f"\\nResults returned: {{len(result.get('data', []))}}")
            print(f"Total count: {{result.get('count', 'N/A')}}")
            data = result.get('data', [])
            if data:
                print("\\nFirst result structure:")
                print(json.dumps(data[0], indent=2))
            return result
        except httpx.HTTPStatusError as e:
            error_msg = f"HTTP error {{e.response.status_code}}: {{e.response.text}}"
            print(f"\\n❌ Error: {{error_msg}}")
            raise ValueError(error_msg)
        except Exception as e:
            error_msg = f"Unexpected error: {{str(e)}}"
            print(f"\\n❌ Error: {{error_msg}}")
            raise ValueError(error_msg)

async def main():
    """Main execution function for BQLv1 web logs debugging"""
    try:
        result = await make_web_logs_call(base_url=BASE_URL, headers=get_headers(), payload=QUERY_PAYLOAD)
        return result
    except Exception as e:
        print(f"\\n❌ Web logs query failed: {{str(e)}}")
        raise

# Execute in Jupyter Notebook:
await main()
'''
    
    return logs_url, query_payload, python_code


def get_botify_analysis_path(app_name, username, project_name, analysis_slug, filename=None):
    """
    🚀 REUSABLE UTILITY: Construct standardized Botify analysis file paths
    
    This eliminates path construction duplication across Botify plugins.
    """
    base_path = Path.cwd() / 'downloads' / app_name / username / project_name / analysis_slug
    return base_path / filename if filename else base_path 