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

import asyncio
import os
import sys
from typing import Any

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

import base64
from datetime import datetime

import aiohttp
import pandas as pd
from rich.console import Console

from pydhis2.core.errors import DHIS2Error
from pydhis2.core.types import DHIS2Config
from pydhis2.dqr.metrics import (
    CompletenessMetrics,
    ConsistencyMetrics,
    MetricResult,
    TimelinessMetrics,
)

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}") from 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("   Auth: Basic authentication")
        console.print(f"   Rate limit: {config.rps} rps")

        # Test invalid configuration
        try:
            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_sync():
    """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(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()
