"""
Test Registry - CI/CD Integration Endpoints

Endpoints for receiving results from CI/CD pipelines.
"""

from datetime import datetime
from typing import Dict

from fastapi import APIRouter, BackgroundTasks

from ...database import get_db_session
from ...repository import TestRepository
from ..api_models import CIResultRequest
from ..config import (
    get_test_runs,
    get_persisted_results,
    is_postgres_available,
)

router = APIRouter()


@router.post("/ci-result")
async def receive_ci_result(result: CIResultRequest, background_tasks: BackgroundTasks):
    """
    Empfaengt Test-Ergebnisse von der CI/CD-Pipeline.

    Wird vom report-test-results Step in .woodpecker/main.yml aufgerufen.

    Flow:
    1. Pipeline fuehrt Tests aus und sammelt JSON-Ergebnisse
    2. Pipeline sendet detaillierte Ergebnisse pro Service hierher
    3. Dieser Endpoint speichert in PostgreSQL
    4. Dashboard zeigt die Daten an

    test_results Format:
    {
        "service": "consent-service",
        "framework": "go",
        "total": 57,
        "passed": 57,
        "failed": 0,
        "skipped": 0,
        "coverage": 75.5
    }
    """
    test_runs = get_test_runs()
    persisted_results = get_persisted_results()

    # Extrahiere Service-spezifische Daten aus test_results
    tr = result.test_results or {}
    service_name = tr.get("service", "ci-pipeline")
    framework = tr.get("framework", "unknown")
    total = tr.get("total", 0)
    passed = tr.get("passed", 0)
    failed = tr.get("failed", 0)
    skipped = tr.get("skipped", 0)
    coverage = tr.get("coverage", 0)

    # Log zur Debugging
    print(f"[CI-RESULT] Pipeline {result.pipeline_id} - Service: {service_name}")
    print(f"[CI-RESULT] Tests: {passed}/{total} passed, {failed} failed, {skipped} skipped")
    print(f"[CI-RESULT] Coverage: {coverage}%, Commit: {result.commit[:8]}")

    # Speichere in PostgreSQL wenn verfuegbar
    if is_postgres_available():
        try:
            with get_db_session() as db:
                repo = TestRepository(db)

                # Erstelle eindeutige Run-ID pro Service
                run_id = f"ci-{result.pipeline_id}-{service_name}"

                # Erstelle Test-Run Eintrag
                run = repo.create_run(
                    run_id=run_id,
                    service=service_name,
                    framework=framework,
                    triggered_by="ci",
                    git_commit=result.commit[:8] if result.commit else None,
                    git_branch=result.branch
                )

                # Markiere als abgeschlossen mit detaillierten Zahlen
                status = "passed" if failed == 0 else "failed"
                repo.complete_run(
                    run_id=run_id,
                    status=status,
                    total_tests=total,
                    passed_tests=passed,
                    failed_tests=failed,
                    skipped_tests=skipped,
                    duration_seconds=0
                )
                print(f"[CI-RESULT] Stored as run_id: {run_id}, status: {status}")

                # WICHTIG: Aktualisiere den In-Memory Cache fuer sofortige Frontend-Updates
                persisted_results[service_name] = {
                    "total": total,
                    "passed": passed,
                    "failed": failed,
                    "last_run": datetime.utcnow().isoformat(),
                    "status": status,
                    "failed_test_ids": []
                }
                print(f"[CI-RESULT] Updated cache for {service_name}: {passed}/{total} passed")

                # Bei fehlgeschlagenen Tests: Backlog-Eintrag erstellen
                if failed > 0:
                    background_tasks.add_task(
                        _create_backlog_entry,
                        service_name,
                        framework,
                        failed,
                        result.pipeline_id,
                        result.commit,
                        result.branch
                    )
                else:
                    # Alle Tests bestanden: Schließe offene Backlog-Einträge
                    background_tasks.add_task(
                        _close_backlog_entry,
                        service_name,
                        result.pipeline_id,
                        result.commit
                    )

                return {
                    "received": True,
                    "run_id": run_id,
                    "service": service_name,
                    "pipeline_id": result.pipeline_id,
                    "status": status,
                    "tests": {"total": total, "passed": passed, "failed": failed},
                    "stored_in": "postgres"
                }

        except Exception as e:
            print(f"[CI-RESULT] PostgreSQL Error: {e}")
            # Fallback auf Memory-Storage
            pass

    # Memory-Fallback
    ci_run = {
        "id": f"ci-{result.pipeline_id}",
        "pipeline_id": result.pipeline_id,
        "commit": result.commit,
        "branch": result.branch,
        "status": result.status,
        "timestamp": datetime.now().isoformat(),
        "test_results": result.test_results
    }
    test_runs.append(ci_run)

    return {
        "received": True,
        "pipeline_id": result.pipeline_id,
        "status": result.status,
        "stored_in": "memory"
    }


async def _create_backlog_entry(
    service_name: str,
    framework: str,
    failed_count: int,
    pipeline_id: str,
    commit: str,
    branch: str
):
    """
    Background-Task: Erstellt Backlog-Eintraege fuer fehlgeschlagene Tests.

    Wird asynchron aufgerufen wenn Tests fehlgeschlagen sind.
    """
    from ...db_models import FailedTestBacklogDB

    print(f"[CI-RESULT] Creating backlog entry for {service_name}: {failed_count} failed tests")

    if is_postgres_available():
        try:
            with get_db_session() as db:
                now = datetime.utcnow()

                # Pruefe ob schon ein offener Backlog-Eintrag fuer diesen Service existiert
                existing = db.query(FailedTestBacklogDB).filter(
                    FailedTestBacklogDB.service == service_name,
                    FailedTestBacklogDB.status == "open"
                ).first()

                if existing:
                    # Aktualisiere existierenden Eintrag
                    existing.last_failed_at = now
                    existing.failure_count += 1
                    existing.error_message = f"{failed_count} Tests fehlgeschlagen in Pipeline {pipeline_id} (Branch: {branch})"
                    db.commit()
                    print(f"[CI-RESULT] Updated existing backlog entry (ID: {existing.id})")
                else:
                    # Neuen Eintrag erstellen
                    backlog = FailedTestBacklogDB(
                        test_name=f"{service_name} Tests",
                        test_file=f"{service_name}/",
                        service=service_name,
                        framework=framework,
                        error_message=f"{failed_count} Tests fehlgeschlagen in Pipeline {pipeline_id} (Branch: {branch})",
                        error_type="TEST_FAILURE",
                        first_failed_at=now,
                        last_failed_at=now,
                        failure_count=1,
                        status="open",
                        priority="high" if failed_count > 5 else "medium"
                    )
                    db.add(backlog)
                    db.commit()
                    print(f"[CI-RESULT] Created new backlog entry (ID: {backlog.id})")

        except Exception as e:
            print(f"[CI-RESULT] Error creating backlog entry: {e}")


async def _close_backlog_entry(
    service_name: str,
    pipeline_id: str,
    commit: str
):
    """
    Background-Task: Schließt Backlog-Einträge wenn alle Tests bestanden.

    Wird asynchron aufgerufen wenn Tests erfolgreich waren.
    """
    from ...db_models import FailedTestBacklogDB

    print(f"[CI-RESULT] Checking for open backlog entries to close for {service_name}")

    if is_postgres_available():
        try:
            with get_db_session() as db:
                now = datetime.utcnow()

                # Finde offene Backlog-Einträge für diesen Service
                open_entries = db.query(FailedTestBacklogDB).filter(
                    FailedTestBacklogDB.service == service_name,
                    FailedTestBacklogDB.status == "open"
                ).all()

                for entry in open_entries:
                    entry.status = "resolved"
                    entry.resolved_at = now
                    entry.resolution_commit = commit[:8] if commit else None
                    entry.resolution_notes = f"Automatisch geschlossen - alle Tests in Pipeline {pipeline_id} bestanden"
                    print(f"[CI-RESULT] Auto-closed backlog entry (ID: {entry.id}) for {service_name}")

                if open_entries:
                    db.commit()
                    print(f"[CI-RESULT] Closed {len(open_entries)} backlog entries for {service_name}")
                else:
                    print(f"[CI-RESULT] No open backlog entries for {service_name}")

        except Exception as e:
            print(f"[CI-RESULT] Error closing backlog entries: {e}")


async def _fetch_and_store_failed_tests(pipeline_id: str, commit: str, branch: str):
    """
    Legacy Background-Task fuer generische Pipeline-Fehler.
    """
    from ...db_models import FailedTestBacklogDB

    print(f"[CI-RESULT] Fetching failed test details for pipeline {pipeline_id}")

    if is_postgres_available():
        try:
            with get_db_session() as db:
                now = datetime.utcnow()

                backlog = FailedTestBacklogDB(
                    test_name=f"CI Pipeline {pipeline_id}",
                    test_file=".woodpecker/main.yml",
                    service="ci-pipeline",
                    framework="woodpecker",
                    error_message=f"Pipeline {pipeline_id} fehlgeschlagen auf Branch {branch}",
                    error_type="CI_FAILURE",
                    first_failed_at=now,
                    last_failed_at=now,
                    failure_count=1,
                    status="open",
                    priority="high"
                )
                db.add(backlog)
                db.commit()
                print(f"[CI-RESULT] Added pipeline failure to backlog (ID: {backlog.id})")

        except Exception as e:
            print(f"[CI-RESULT] Error adding to backlog: {e}")
