#!/usr/bin/env python3
"""
Test pydhis2 connection to DHIS2 official demo instance
Use simplified HTTP client to verify basic functionality
"""

import asyncio
import sys
import os
from typing import Dict, Any, List

# 添加当前目录到路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from pydhis2.core.types import DHIS2Config
from pydhis2.core.errors import DHIS2Error

import aiohttp
import base64
import pandas as pd
from datetime import datetime
from rich.console import Console
from rich.table import Table

from pydhis2.dqr.metrics import CompletenessMetrics, ConsistencyMetrics, TimelinessMetrics, MetricResult

console = Console()

class DemoTestClient:
    """Simplified demo test client"""
    
    def __init__(self, base_url: str, username: str, password: str):
        # 规范化API基础URL，确保正确的/api后缀
        self.base_url = self._normalize_api_base(base_url)
        self.username = username
        self.password = password
        self.session = None
    
    def _normalize_api_base(self, base_url: str) -> str:
        """Normalize API base: ensure exactly one /api suffix"""
        b = base_url.rstrip("/")
        if b.endswith("/api"):
            return b
        return b + "/api"
    
    async def __aenter__(self):
        # Create Basic authentication header
        credentials = f"{self.username}:{self.password}"
        encoded = base64.b64encode(credentials.encode('utf-8')).decode('ascii')
        
        headers = {
            'Authorization': f'Basic {encoded}',
            'User-Agent': 'pydhis2-demo-test/0.1.0',
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        }
        
        timeout = aiohttp.ClientTimeout(total=30)
        # Use default connector to avoid aiodns issues on Windows
        connector = aiohttp.TCPConnector(use_dns_cache=False, resolver=aiohttp.DefaultResolver())
        self.session = aiohttp.ClientSession(headers=headers, timeout=timeout, connector=connector)
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()
    
    async def get(self, endpoint: str, params=None) -> Dict[str, Any]:
        """Make GET request"""
        url = f"{self.base_url}/{endpoint.lstrip('/')}"
        
        try:
            async with self.session.get(url, params=params) as response:
                if response.status == 401:
                    raise DHIS2Error("Authentication failed, please check username and password")
                elif response.status == 404:
                    raise DHIS2Error("Endpoint does not exist")
                elif response.status >= 400:
                    text = await response.text()
                    console.print(f"🔍 Debug info - Status code: {response.status}")
                    console.print(f"🔍 Debug info - URL: {url}")
                    console.print(f"🔍 Debug info - First 200 characters of response: {text[:200]}")
                    raise DHIS2Error(f"HTTP {response.status}: {text[:200]}")
                
                content_type = response.headers.get('content-type', '')
                if 'application/json' not in content_type:
                    text = await response.text()
                    console.print(f"🔍 Debug info - Content-Type: {content_type}")
                    console.print(f"🔍 Debug info - First 200 characters of response: {text[:200]}")
                    if 'login' in text.lower() or 'dhis-web-login' in text:
                        raise DHIS2Error("Redirected to login page, authentication may have failed")
                    raise DHIS2Error(f"Expected JSON response, but received: {content_type}")
                
                return await response.json()
        except aiohttp.ClientError as e:
            raise DHIS2Error(f"Network error: {e}")

def generate_html_report(metrics_results: List[MetricResult], title: str = "DHIS2 Data Quality Report") -> str:
    """Generate HTML data quality report"""
    
    # HTML模板
    html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{title}</title>
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }}
        .container {{
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        .header {{
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 3px solid #2196F3;
        }}
        .header h1 {{
            color: #1976D2;
            margin: 0;
            font-size: 2.5em;
        }}
        .header p {{
            color: #666;
            margin: 10px 0 0 0;
            font-size: 1.1em;
        }}
        .summary {{
            display: flex;
            justify-content: space-around;
            margin-bottom: 30px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 6px;
        }}
        .summary-item {{
            text-align: center;
        }}
        .summary-item .number {{
            font-size: 2em;
            font-weight: bold;
            margin-bottom: 5px;
        }}
        .summary-item .label {{
            color: #666;
            font-size: 0.9em;
        }}
        .pass {{ color: #4CAF50; }}
        .warning {{ color: #FF9800; }}
        .fail {{ color: #F44336; }}
        .metrics-grid {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }}
        .metric-card {{
            border: 1px solid #ddd;
            border-radius: 6px;
            padding: 20px;
            background: white;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
        }}
        .metric-header {{
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }}
        .metric-name {{
            font-size: 1.2em;
            font-weight: bold;
            color: #333;
        }}
        .metric-status {{
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 0.8em;
            font-weight: bold;
            text-transform: uppercase;
        }}
        .status-pass {{
            background: #E8F5E8;
            color: #4CAF50;
        }}
        .status-warning {{
            background: #FFF3E0;
            color: #FF9800;
        }}
        .status-fail {{
            background: #FFEBEE;
            color: #F44336;
        }}
        .metric-value {{
            font-size: 2em;
            font-weight: bold;
            margin: 10px 0;
        }}
        .metric-message {{
            color: #666;
            margin-bottom: 15px;
        }}
        .metric-details {{
            background: #f8f9fa;
            padding: 10px;
            border-radius: 4px;
            font-size: 0.9em;
        }}
        .detail-item {{
            margin: 5px 0;
        }}
        .footer {{
            margin-top: 30px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
            text-align: center;
            color: #666;
            font-size: 0.9em;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>{title}</h1>
            <p>Generated at: {timestamp}</p>
        </div>
        
        <div class="summary">
            <div class="summary-item">
                <div class="number pass">{pass_count}</div>
                <div class="label">Passed</div>
            </div>
            <div class="summary-item">
                <div class="number warning">{warning_count}</div>
                <div class="label">Warnings</div>
            </div>
            <div class="summary-item">
                <div class="number fail">{fail_count}</div>
                <div class="label">Failed</div>
            </div>
            <div class="summary-item">
                <div class="number">{total_count}</div>
                <div class="label">Total</div>
            </div>
        </div>
        
        <div class="metrics-grid">
            {metrics_html}
        </div>
        
        <div class="footer">
            <p>Generated by pydhis2 | WHO Data Quality Review Framework</p>
        </div>
    </div>
</body>
</html>
    """
    
    # 计算统计信息
    pass_count = sum(1 for m in metrics_results if m.status == 'pass')
    warning_count = sum(1 for m in metrics_results if m.status == 'warning')
    fail_count = sum(1 for m in metrics_results if m.status == 'fail')
    total_count = len(metrics_results)
    
    # 生成指标卡片HTML
    metrics_html = ""
    for metric in metrics_results:
        # 格式化指标值
        if metric.value <= 1.0:
            value_display = f"{metric.value:.1%}"
        else:
            value_display = f"{metric.value:.2f}"
        
        # 生成详情HTML
        details_html = ""
        if metric.details:
            for key, value in metric.details.items():
                if isinstance(value, float):
                    if value <= 1.0:
                        formatted_value = f"{value:.1%}"
                    else:
                        formatted_value = f"{value:.2f}"
                else:
                    formatted_value = str(value)
                details_html += f'<div class="detail-item"><strong>{key}:</strong> {formatted_value}</div>'
        
        metric_card = f"""
        <div class="metric-card">
            <div class="metric-header">
                <div class="metric-name">{metric.metric_name.replace('_', ' ').title()}</div>
                <div class="metric-status status-{metric.status}">{metric.status}</div>
            </div>
            <div class="metric-value {metric.status}">{value_display}</div>
            <div class="metric-message">{metric.message}</div>
            {f'<div class="metric-details">{details_html}</div>' if details_html else ''}
        </div>
        """
        metrics_html += metric_card
    
    # 填充模板
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    return html_template.format(
        title=title,
        timestamp=timestamp,
        pass_count=pass_count,
        warning_count=warning_count,
        fail_count=fail_count,
        total_count=total_count,
        metrics_html=metrics_html
    )

async def test_dhis2_instance(base_url: str, username: str, password: str):
    """Test DHIS2 instance connection"""
    console.print(f"\n🌐 Testing: {base_url}")
    console.print(f"👤 Authentication: {username}")
    
    async with DemoTestClient(base_url, username, password) as client:
        try:
            # 1. Test /api/me
            console.print("🔍 Testing user information...")
            me_data = await client.get("me")
            console.print(f"✅ User: {me_data.get('name', 'Unknown')}")
            console.print(f"   ID: {me_data.get('id', 'N/A')}")

            # 2. Test system information
            console.print("📊 Testing system information...")
            system_info = await client.get("system/info")
            console.print(f"✅ DHIS2 version: {system_info.get('version', 'Unknown')}")
            console.print(f"   Build time: {system_info.get('buildTime', 'Unknown')}")
            
            # 3. Test simple Analytics query (using verified dimension parameters)
            console.print("📈 Testing Analytics...")
            analytics_params = {
                'dimension': [
                    'dx:ReUHfIn0pTQ;fbfJHSPpUQD',  # Indicator/Data element example UID
                    'pe:LAST_12_MONTHS',           # Last 12 months
                    'ou:ImspTQPwCqd'               # Demo root organization UID
                ],
                'displayProperty': 'NAME',
                'skipMeta': 'false',
                'skipData': 'false'
            }

            analytics_data = await client.get("analytics", analytics_params)
            headers = analytics_data.get('headers', [])
            rows = analytics_data.get('rows', [])
            console.print(f"✅ Analytics: {len(headers)} columns, {len(rows)} rows")

            # 4. Test data elements
            console.print("🔢 Testing data elements...")
            elements_data = await client.get("dataElements", {'pageSize': 3, 'fields': 'id,name'})
            elements = elements_data.get('dataElements', [])
            console.print(f"✅ Data elements: found {len(elements)} items")
            
            console.print("🎉 All tests passed!")
            return True

        except Exception as e:
            console.print(f"❌ Test failed: {e}")
            return False

async def test_dqr_html_generation(base_url: str, username: str, password: str):
    """Test data quality report HTML generation"""
    console.print("\n📊 Testing data quality report HTML generation...")
    
    async with DemoTestClient(base_url, username, password) as client:
        try:
            # 1. Get data value sets data for DQR analysis
            console.print("📥 Fetching data value sets...")
            params = {
                'dataSet': 'pBOMPrpg1QX',  # Child Health dataset
                'orgUnit': 'ImspTQPwCqd', # Sierra Leone
                'period': '2023',
                'children': 'true'
            }

            datavalue_data = await client.get("dataValueSets", params)
            data_values = datavalue_data.get('dataValues', [])

            if not data_values:
                console.print("⚠️ No data value sets retrieved, trying to get data from Analytics endpoint...")
                # Try to get data from Analytics (using verified parameters)
                analytics_params = {
                    'dimension': [
                        'dx:ReUHfIn0pTQ;fbfJHSPpUQD',  # Indicators/Data elements
                        'pe:LAST_12_MONTHS',           # Last 12 months
                        'ou:ImspTQPwCqd'               # Root organization
                    ],
                    'displayProperty': 'NAME'
                }
                analytics_data = await client.get("analytics", analytics_params)

                if 'rows' in analytics_data and analytics_data['rows']:
                    # Convert Analytics data to data value format
                    headers = analytics_data.get('headers', [])
                    data_values = []
                    for row in analytics_data['rows']:
                        if len(row) >= 4:  # At least 4 columns of data
                            data_values.append({
                                'dataElement': row[0] if len(headers) > 0 else 'unknown',
                                'period': row[1] if len(headers) > 1 else '2023',
                                'orgUnit': row[2] if len(headers) > 2 else 'unknown',
                                'value': row[3] if len(headers) > 3 else '0',
                                'lastUpdated': '2024-01-01T10:00:00'
                            })
                    console.print(f"✅ Retrieved {len(data_values)} records from Analytics")
                else:
                    console.print("❌ Unable to retrieve any data from API, skipping DQR test")
                    return False
            
            console.print(f"✅ Retrieved {len(data_values)} data values")

            # 2. Convert to DataFrame
            df = pd.DataFrame(data_values)
            console.print("✅ Data converted to DataFrame successfully")

            # 3. Run DQR metrics
            console.print("🔍 Running data quality metrics...")

            # Completeness metrics
            completeness_metrics = CompletenessMetrics()
            completeness_results = completeness_metrics.calculate(df)

            # Consistency metrics
            consistency_metrics = ConsistencyMetrics()
            consistency_results = consistency_metrics.calculate(df)

            # Timeliness metrics
            timeliness_metrics = TimelinessMetrics()
            timeliness_results = timeliness_metrics.calculate(df)

            # Merge all results
            all_results = completeness_results + consistency_results + timeliness_results
            console.print(f"✅ Calculated {len(all_results)} quality metrics")

            # 4. Generate HTML report
            console.print("📄 Generating HTML report...")
            html_content = generate_html_report(
                all_results,
                title="DHIS2 Demo Instance Data Quality Report"
            )

            # 5. Save HTML file
            output_file = "dqr_demo_report.html"
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(html_content)

            console.print(f"✅ HTML report generated: {output_file}")

            # 6. Display results summary
            console.print("\n📋 Quality metrics summary:")
            for result in all_results:
                status_emoji = {"pass": "✅", "warning": "⚠️", "fail": "❌"}
                emoji = status_emoji.get(result.status, "❓")
                console.print(f"  {emoji} {result.metric_name}: {result.value:.1%} ({result.status})")

            return True

        except Exception as e:
            console.print(f"❌ DQR HTML generation test failed: {e}")
            import traceback
            console.print(f"Detailed error: {traceback.format_exc()}")
            return False

async def test_config_system():
    """Test configuration system"""
    console.print("\n⚙️ Testing pydhis2 configuration system...")

    try:
        # Test valid configuration (using stable instance)
        config = DHIS2Config(
            base_url="https://play.im.dhis2.org/stable-2-42-1",
            auth=("admin", "district"),
            rps=5.0
        )
        console.print("✅ Configuration created successfully")
        console.print(f"   URL: {config.base_url}")
        console.print(f"   Auth: Basic authentication")
        console.print(f"   Rate limit: {config.rps} rps")

        # Test invalid configuration
        try:
            invalid_config = DHIS2Config(
                base_url="invalid-url",
                auth=("user", "pass")
            )
            # Note: URL validation might be lenient, this is acceptable
            console.print("✅ Configuration accepts various URL formats")
        except Exception:
            console.print("✅ Correctly rejected invalid URL")

        return True
    except Exception as e:
        console.print(f"❌ Configuration test failed: {e}")
        return False

async def main():
    """Main function"""
    console.print("🚀 pydhis2 Demo Instance Test")
    console.print("=" * 50)

    # Test configuration system
    config_ok = await test_config_system()

    # Test stable demo instances (updated from working configuration)
    demo_instances = [
        ("https://play.im.dhis2.org/stable-2-42-1", "admin", "district"),
        ("https://play.dhis2.org/dev", "admin", "district"),
        ("https://play.dhis2.org/41.2.2", "admin", "district"),  # Backup
    ]

    successful_tests = 0
    total_tests = len(demo_instances) + 1  # +1 for config test

    if config_ok:
        successful_tests += 1

    successful_instance = None
    for base_url, username, password in demo_instances:
        try:
            if await test_dhis2_instance(base_url, username, password):
                successful_tests += 1
                successful_instance = (base_url, username, password)
                break  # One working instance is enough
        except Exception as e:
            console.print(f"❌ {base_url} test exception: {e}")

    # If there's a working instance, test DQR HTML generation
    if successful_instance:
        try:
            console.print("\n" + "="*50)
            if await test_dqr_html_generation(*successful_instance):
                successful_tests += 1
        except Exception as e:
            console.print(f"❌ DQR HTML test exception: {e}")

    total_tests += 1  # DQR test also counts as a test

    # Summary
    console.print("\n" + "=" * 50)
    console.print(f"🎯 Test results: {successful_tests}/{total_tests} successful")

    if successful_tests >= 3:  # Config test + demo instance + DQR HTML
        console.print("🎉 pydhis2 complete functionality verification successful!")
        console.print("✅ Configuration system working")
        console.print("✅ Can connect to DHIS2 instance")
        console.print("✅ Basic API calls working")
        console.print("✅ Data quality report HTML generation working")
        return 0
    elif successful_tests >= 2:  # Config test + at least one demo instance
        console.print("🎉 pydhis2 basic functionality verification successful!")
        console.print("✅ Configuration system working")
        console.print("✅ Can connect to DHIS2 instance")
        console.print("✅ Basic API calls working")
        console.print("⚠️ DQR HTML generation test not passed")
        return 0
    else:
        console.print("⚠️ Some tests failed, need further checking")
        return 1

def main():
    """Entry point for console script"""
    # Set event loop policy for Windows compatibility
    if sys.platform == 'win32':
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    exit_code = asyncio.run(async_main())
    sys.exit(exit_code)


async def async_main():
    """Main test function"""
    console.print("🚀 pydhis2 Demo Instance Test")
    console.print("=" * 50)

    # Test configuration system
    config_ok = await test_config_system()

    # Test stable demo instances (updated from working configuration)
    demo_instances = [
        ("https://play.im.dhis2.org/stable-2-42-1", "admin", "district"),
        ("https://play.dhis2.org/dev", "admin", "district"),
        ("https://play.dhis2.org/41.2.2", "admin", "district"),  # Backup
    ]

    successful_tests = 0
    total_tests = len(demo_instances) + 1  # +1 for config test

    if config_ok:
        successful_tests += 1

    successful_instance = None
    for base_url, username, password in demo_instances:
        try:
            if await test_dhis2_instance(base_url, username, password):
                successful_tests += 1
                successful_instance = (base_url, username, password)
                break  # One working instance is enough
        except Exception as e:
            console.print(f"❌ {base_url} test exception: {e}")

    # If there's a working instance, test DQR HTML generation
    if successful_instance:
        try:
            console.print("\n" + "="*50)
            if await test_dqr_html_generation(*successful_instance):
                successful_tests += 1
        except Exception as e:
            console.print(f"❌ DQR HTML test exception: {e}")

    total_tests += 1  # DQR test also counts as a test

    # Summary
    console.print("\n" + "=" * 50)
    console.print(f"🎯 Test results: {successful_tests}/{total_tests} successful")

    if successful_tests >= 3:  # Config test + demo instance + DQR HTML
        console.print("🎉 pydhis2 complete functionality verification successful!")
        console.print("✅ Configuration system working")
        console.print("✅ Can connect to DHIS2 instance")
        console.print("✅ Basic API calls working")
        console.print("✅ Data quality report HTML generation working")
        return 0
    elif successful_tests >= 2:  # Config test + at least one demo instance
        console.print("🎉 pydhis2 basic functionality verification successful!")
        console.print("✅ Configuration system working")
        console.print("✅ Can connect to DHIS2 instance")
        console.print("✅ Basic API calls working")
        console.print("⚠️ DQR HTML generation test not passed")
        return 0
    else:
        console.print("⚠️ Some tests failed, need further checking")
        return 1


if __name__ == "__main__":
    main()
