"""
Jest Test Executor

Executes Jest tests for JavaScript/TypeScript projects.
"""

import os
import re
import json
import subprocess
from pathlib import Path
from typing import Dict

from ..config import get_running_tests


async def run_jest_tests(base_path: Path, service_id: str = "") -> Dict:
    """Fuehrt Jest-Tests aus"""
    running_tests = get_running_tests()

    if not base_path.exists():
        return {"passed": 0, "failed": 0, "total": 0, "output": f"Pfad existiert nicht: {base_path}", "failed_test_ids": []}

    running_tests[service_id] = {
        "current_file": "Starte Jest...",
        "files_done": 0,
        "files_total": 1,
        "passed": 0,
        "failed": 0,
        "status": "running"
    }

    # Prüfe ob Node.js verfügbar ist
    try:
        node_check = subprocess.run(["node", "--version"], capture_output=True, timeout=5)
        if node_check.returncode != 0:
            return {"passed": 0, "failed": 0, "total": 0, "output": "Node.js nicht installiert", "failed_test_ids": []}
    except:
        return {"passed": 0, "failed": 0, "total": 0, "output": "Node.js nicht verfuegbar", "failed_test_ids": []}

    try:
        # Wechsle ins Projektverzeichnis und fuehre Jest aus
        env = os.environ.copy()
        env["CI"] = "true"  # Nicht-interaktiver Modus

        result = subprocess.run(
            ["npm", "test", "--", "--json", "--passWithNoTests"],
            cwd=str(base_path),
            capture_output=True,
            text=True,
            timeout=300,
            env=env,
        )

        output = result.stdout + result.stderr
        passed = 0
        failed = 0
        failed_test_ids = []

        # Versuche JSON-Output zu parsen
        try:
            # Jest JSON beginnt mit {"num... - finde den Start
            json_start = output.find('{"num')
            if json_start == -1:
                json_start = output.rfind('{"')

            if json_start != -1:
                json_str = output[json_start:]
                # Versuche JSON zu parsen mit json.JSONDecoder
                decoder = json.JSONDecoder()
                try:
                    jest_result, _ = decoder.raw_decode(json_str)
                    passed = jest_result.get("numPassedTests", 0)
                    failed = jest_result.get("numFailedTests", 0)

                    # Extrahiere fehlgeschlagene Tests
                    for test_result in jest_result.get("testResults", []):
                        for assertion in test_result.get("assertionResults", []):
                            if assertion.get("status") == "failed":
                                failed_test_ids.append({
                                    "id": f"{test_result.get('name', '')}::{assertion.get('fullName', '')}",
                                    "name": assertion.get("fullName", ""),
                                    "file_path": test_result.get("name", ""),
                                    "error_message": " ".join(assertion.get("failureMessages", []))[:500],
                                    "error_type": "assertion",
                                    "suggestion": "Pruefe die Test-Assertions und erwarteten Werte",
                                })
                except json.JSONDecodeError:
                    # Fallback: Parse Text-Output mit Regex
                    for line in output.split("\n"):
                        if "passed" in line.lower():
                            match = re.search(r"(\d+)\s+passed", line)
                            if match:
                                passed = int(match.group(1))
                        if "failed" in line.lower():
                            match = re.search(r"(\d+)\s+failed", line)
                            if match:
                                failed = int(match.group(1))
        except Exception:
            # Allgemeiner Fallback: Parse Text-Output
            for line in output.split("\n"):
                if "passed" in line.lower():
                    match = re.search(r"(\d+)\s+passed", line)
                    if match:
                        passed = int(match.group(1))
                if "failed" in line.lower():
                    match = re.search(r"(\d+)\s+failed", line)
                    if match:
                        failed = int(match.group(1))

        running_tests[service_id] = {
            "current_file": "Abgeschlossen",
            "files_done": 1,
            "files_total": 1,
            "passed": passed,
            "failed": failed,
            "status": "completed"
        }

        return {
            "passed": passed,
            "failed": failed,
            "total": passed + failed,
            "output": output[:5000],
            "failed_test_ids": failed_test_ids,
        }
    except subprocess.TimeoutExpired:
        return {"passed": 0, "failed": 0, "total": 0, "output": "Timeout nach 5 Minuten", "failed_test_ids": []}
    except Exception as e:
        return {"passed": 0, "failed": 0, "total": 0, "output": str(e), "failed_test_ids": []}
