"""
Mail Test API - Test Runner fuer E-Mail Integration (IMAP/SMTP/KI-Analyse)
Endpoint: /api/admin/mail-tests
"""

from fastapi import APIRouter
from pydantic import BaseModel
from typing import List, Optional, Literal
import httpx
import asyncio
import time
import os
import socket

router = APIRouter(prefix="/api/admin/mail-tests", tags=["Mail Tests"])

# ==============================================
# Models
# ==============================================

class TestResult(BaseModel):
    name: str
    description: str
    expected: str
    actual: str
    status: Literal["passed", "failed", "pending", "skipped"]
    duration_ms: float
    error_message: Optional[str] = None


class TestCategoryResult(BaseModel):
    category: str
    display_name: str
    description: str
    tests: List[TestResult]
    passed: int
    failed: int
    total: int


class FullTestResults(BaseModel):
    categories: List[TestCategoryResult]
    total_passed: int
    total_failed: int
    total_tests: int
    duration_ms: float


# ==============================================
# Configuration
# ==============================================

MAILPIT_URL = os.getenv("MAILPIT_URL", "http://mailpit:8025")
SMTP_HOST = os.getenv("SMTP_HOST", "mailpit")
SMTP_PORT = int(os.getenv("SMTP_PORT", "1025"))
IMAP_HOST = os.getenv("IMAP_HOST", "mailpit")
IMAP_PORT = int(os.getenv("IMAP_PORT", "1143"))
BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:8000")


# ==============================================
# Test Implementations
# ==============================================

async def test_smtp_connection() -> TestResult:
    """Test SMTP Server Connection"""
    start = time.time()
    try:
        # Try to connect to SMTP port
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)
        result = sock.connect_ex((SMTP_HOST, SMTP_PORT))
        sock.close()
        duration = (time.time() - start) * 1000

        if result == 0:
            return TestResult(
                name="SMTP Server Verbindung",
                description="Prueft ob der SMTP Server fuer ausgehende E-Mails erreichbar ist",
                expected=f"Verbindung zu {SMTP_HOST}:{SMTP_PORT}",
                actual=f"SMTP Server erreichbar",
                status="passed",
                duration_ms=duration
            )
        else:
            return TestResult(
                name="SMTP Server Verbindung",
                description="Prueft ob der SMTP Server fuer ausgehende E-Mails erreichbar ist",
                expected=f"Verbindung zu {SMTP_HOST}:{SMTP_PORT}",
                actual=f"Verbindung fehlgeschlagen (Code: {result})",
                status="failed",
                duration_ms=duration,
                error_message=f"Socket-Fehler: {result}"
            )
    except Exception as e:
        return TestResult(
            name="SMTP Server Verbindung",
            description="Prueft ob der SMTP Server fuer ausgehende E-Mails erreichbar ist",
            expected=f"Verbindung zu {SMTP_HOST}:{SMTP_PORT}",
            actual=f"Fehler: {str(e)}",
            status="failed",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_imap_connection() -> TestResult:
    """Test IMAP Server Connection"""
    start = time.time()
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)
        result = sock.connect_ex((IMAP_HOST, IMAP_PORT))
        sock.close()
        duration = (time.time() - start) * 1000

        if result == 0:
            return TestResult(
                name="IMAP Server Verbindung",
                description="Prueft ob der IMAP Server fuer eingehende E-Mails erreichbar ist",
                expected=f"Verbindung zu {IMAP_HOST}:{IMAP_PORT}",
                actual=f"IMAP Server erreichbar",
                status="passed",
                duration_ms=duration
            )
        else:
            return TestResult(
                name="IMAP Server Verbindung",
                description="Prueft ob der IMAP Server fuer eingehende E-Mails erreichbar ist",
                expected=f"Verbindung zu {IMAP_HOST}:{IMAP_PORT}",
                actual=f"Verbindung fehlgeschlagen",
                status="skipped",
                duration_ms=duration,
                error_message=f"IMAP nicht konfiguriert oder nicht erreichbar"
            )
    except Exception as e:
        return TestResult(
            name="IMAP Server Verbindung",
            description="Prueft ob der IMAP Server fuer eingehende E-Mails erreichbar ist",
            expected=f"Verbindung zu {IMAP_HOST}:{IMAP_PORT}",
            actual=f"Nicht verfuegbar",
            status="skipped",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_mailpit_api() -> TestResult:
    """Test Mailpit Web API (Development Mail Catcher)"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(f"{MAILPIT_URL}/api/v1/info")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                data = response.json()
                version = data.get("Version", "unknown")
                return TestResult(
                    name="Mailpit Web API",
                    description="Prueft ob die Mailpit Test-Oberflaeche verfuegbar ist",
                    expected="HTTP 200 mit Version-Info",
                    actual=f"Mailpit v{version} aktiv",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="Mailpit Web API",
                    description="Prueft ob die Mailpit Test-Oberflaeche verfuegbar ist",
                    expected="HTTP 200 mit Version-Info",
                    actual=f"HTTP {response.status_code}",
                    status="failed",
                    duration_ms=duration,
                    error_message=f"Unerwarteter Status: {response.status_code}"
                )
    except Exception as e:
        return TestResult(
            name="Mailpit Web API",
            description="Prueft ob die Mailpit Test-Oberflaeche verfuegbar ist",
            expected="HTTP 200 mit Version-Info",
            actual=f"Fehler: {str(e)}",
            status="failed",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_mailpit_messages() -> TestResult:
    """Test Mailpit Message Storage"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(f"{MAILPIT_URL}/api/v1/messages")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                data = response.json()
                total = data.get("total", 0)
                return TestResult(
                    name="Mailpit Message Storage",
                    description="Prueft ob E-Mails im Entwicklungsmodus abgefangen werden",
                    expected="Nachrichtenliste abrufbar",
                    actual=f"{total} Nachrichten gespeichert",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="Mailpit Message Storage",
                    description="Prueft ob E-Mails im Entwicklungsmodus abgefangen werden",
                    expected="Nachrichtenliste abrufbar",
                    actual=f"HTTP {response.status_code}",
                    status="failed",
                    duration_ms=duration,
                    error_message=f"API-Fehler: {response.status_code}"
                )
    except Exception as e:
        return TestResult(
            name="Mailpit Message Storage",
            description="Prueft ob E-Mails im Entwicklungsmodus abgefangen werden",
            expected="Nachrichtenliste abrufbar",
            actual=f"Fehler: {str(e)}",
            status="failed",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_email_templates_api() -> TestResult:
    """Test Email Templates API"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(f"{BACKEND_URL}/api/email-templates")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                data = response.json()
                count = len(data) if isinstance(data, list) else data.get("total", 0)
                return TestResult(
                    name="E-Mail Templates API",
                    description="Prueft ob die E-Mail-Vorlagen-Verwaltung verfuegbar ist",
                    expected="Template-Liste abrufbar",
                    actual=f"{count} Templates verfuegbar",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="E-Mail Templates API",
                    description="Prueft ob die E-Mail-Vorlagen-Verwaltung verfuegbar ist",
                    expected="Template-Liste abrufbar",
                    actual=f"HTTP {response.status_code}",
                    status="failed",
                    duration_ms=duration,
                    error_message=f"API nicht verfuegbar"
                )
    except Exception as e:
        return TestResult(
            name="E-Mail Templates API",
            description="Prueft ob die E-Mail-Vorlagen-Verwaltung verfuegbar ist",
            expected="Template-Liste abrufbar",
            actual=f"Fehler: {str(e)}",
            status="failed",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_email_settings_api() -> TestResult:
    """Test Email Settings API"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(f"{BACKEND_URL}/api/email-templates/settings")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                data = response.json()
                sender = data.get("sender_email", "nicht konfiguriert")
                return TestResult(
                    name="E-Mail Einstellungen",
                    description="Prueft ob die globalen E-Mail-Einstellungen (Absender, Logo) verfuegbar sind",
                    expected="Einstellungen abrufbar",
                    actual=f"Absender: {sender}",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="E-Mail Einstellungen",
                    description="Prueft ob die globalen E-Mail-Einstellungen (Absender, Logo) verfuegbar sind",
                    expected="Einstellungen abrufbar",
                    actual=f"HTTP {response.status_code}",
                    status="failed",
                    duration_ms=duration,
                    error_message=f"Einstellungen nicht verfuegbar"
                )
    except Exception as e:
        return TestResult(
            name="E-Mail Einstellungen",
            description="Prueft ob die globalen E-Mail-Einstellungen (Absender, Logo) verfuegbar sind",
            expected="Einstellungen abrufbar",
            actual=f"Fehler: {str(e)}",
            status="failed",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_llm_analysis_endpoint() -> TestResult:
    """Test LLM Mail Analysis Endpoint"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            # Check if LLM gateway is enabled
            response = await client.get(f"{BACKEND_URL}/llm/health")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                return TestResult(
                    name="KI E-Mail Analyse",
                    description="Prueft ob die LLM-basierte E-Mail-Analyse verfuegbar ist",
                    expected="LLM Gateway aktiv",
                    actual="KI-Analyse bereit",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="KI E-Mail Analyse",
                    description="Prueft ob die LLM-basierte E-Mail-Analyse verfuegbar ist",
                    expected="LLM Gateway aktiv",
                    actual="LLM Gateway nicht aktiviert",
                    status="skipped",
                    duration_ms=duration,
                    error_message="LLM_GATEWAY_ENABLED=false"
                )
    except Exception as e:
        return TestResult(
            name="KI E-Mail Analyse",
            description="Prueft ob die LLM-basierte E-Mail-Analyse verfuegbar ist",
            expected="LLM Gateway aktiv",
            actual="Nicht verfuegbar",
            status="skipped",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


async def test_gfk_integration() -> TestResult:
    """Test GFK (Gewaltfreie Kommunikation) Integration"""
    start = time.time()
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.get(f"{BACKEND_URL}/v1/communication/health")
            duration = (time.time() - start) * 1000

            if response.status_code == 200:
                return TestResult(
                    name="GFK Integration",
                    description="Prueft ob die Gewaltfreie-Kommunikation Analyse fuer Elternbriefe aktiv ist",
                    expected="Communication Service verfuegbar",
                    actual="GFK-Analyse bereit",
                    status="passed",
                    duration_ms=duration
                )
            else:
                return TestResult(
                    name="GFK Integration",
                    description="Prueft ob die Gewaltfreie-Kommunikation Analyse fuer Elternbriefe aktiv ist",
                    expected="Communication Service verfuegbar",
                    actual=f"HTTP {response.status_code}",
                    status="skipped",
                    duration_ms=duration,
                    error_message="GFK-Service nicht konfiguriert"
                )
    except Exception as e:
        return TestResult(
            name="GFK Integration",
            description="Prueft ob die Gewaltfreie-Kommunikation Analyse fuer Elternbriefe aktiv ist",
            expected="Communication Service verfuegbar",
            actual="Nicht verfuegbar",
            status="skipped",
            duration_ms=(time.time() - start) * 1000,
            error_message=str(e)
        )


# ==============================================
# Category Runners
# ==============================================

async def run_smtp_tests() -> TestCategoryResult:
    """Run SMTP-related tests"""
    tests = await asyncio.gather(
        test_smtp_connection(),
        test_mailpit_api(),
        test_mailpit_messages(),
    )

    passed = sum(1 for t in tests if t.status == "passed")
    failed = sum(1 for t in tests if t.status == "failed")

    return TestCategoryResult(
        category="smtp",
        display_name="SMTP / Ausgehende E-Mails",
        description="Tests fuer den E-Mail-Versand",
        tests=list(tests),
        passed=passed,
        failed=failed,
        total=len(tests)
    )


async def run_imap_tests() -> TestCategoryResult:
    """Run IMAP-related tests"""
    tests = await asyncio.gather(
        test_imap_connection(),
    )

    passed = sum(1 for t in tests if t.status == "passed")
    failed = sum(1 for t in tests if t.status == "failed")

    return TestCategoryResult(
        category="imap",
        display_name="IMAP / Eingehende E-Mails",
        description="Tests fuer den E-Mail-Empfang",
        tests=list(tests),
        passed=passed,
        failed=failed,
        total=len(tests)
    )


async def run_templates_tests() -> TestCategoryResult:
    """Run Email Templates tests"""
    tests = await asyncio.gather(
        test_email_templates_api(),
        test_email_settings_api(),
    )

    passed = sum(1 for t in tests if t.status == "passed")
    failed = sum(1 for t in tests if t.status == "failed")

    return TestCategoryResult(
        category="templates",
        display_name="E-Mail Templates",
        description="Tests fuer die E-Mail-Vorlagen-Verwaltung",
        tests=list(tests),
        passed=passed,
        failed=failed,
        total=len(tests)
    )


async def run_ai_tests() -> TestCategoryResult:
    """Run AI Analysis tests"""
    tests = await asyncio.gather(
        test_llm_analysis_endpoint(),
        test_gfk_integration(),
    )

    passed = sum(1 for t in tests if t.status == "passed")
    failed = sum(1 for t in tests if t.status == "failed")

    return TestCategoryResult(
        category="ai-analysis",
        display_name="KI-Analyse",
        description="Tests fuer die KI-basierte E-Mail-Analyse",
        tests=list(tests),
        passed=passed,
        failed=failed,
        total=len(tests)
    )


# ==============================================
# API Endpoints
# ==============================================

@router.post("/{category}", response_model=TestCategoryResult)
async def run_category_tests(category: str):
    """Run tests for a specific category"""
    runners = {
        "smtp": run_smtp_tests,
        "imap": run_imap_tests,
        "templates": run_templates_tests,
        "ai-analysis": run_ai_tests,
    }

    if category not in runners:
        return TestCategoryResult(
            category=category,
            display_name=f"Unbekannt: {category}",
            description="Kategorie nicht gefunden",
            tests=[],
            passed=0,
            failed=0,
            total=0
        )

    return await runners[category]()


@router.post("/run-all", response_model=FullTestResults)
async def run_all_tests():
    """Run all mail tests"""
    start = time.time()

    categories = await asyncio.gather(
        run_smtp_tests(),
        run_imap_tests(),
        run_templates_tests(),
        run_ai_tests(),
    )

    total_passed = sum(c.passed for c in categories)
    total_failed = sum(c.failed for c in categories)
    total_tests = sum(c.total for c in categories)

    return FullTestResults(
        categories=list(categories),
        total_passed=total_passed,
        total_failed=total_failed,
        total_tests=total_tests,
        duration_ms=(time.time() - start) * 1000
    )


@router.get("/categories")
async def get_categories():
    """Get available test categories"""
    return {
        "categories": [
            {"id": "smtp", "name": "SMTP", "description": "Ausgehende E-Mails"},
            {"id": "imap", "name": "IMAP", "description": "Eingehende E-Mails"},
            {"id": "templates", "name": "Templates", "description": "E-Mail-Vorlagen"},
            {"id": "ai-analysis", "name": "KI-Analyse", "description": "LLM & GFK"},
        ]
    }
