"""
Dashboard API Integration Tests

Tests Dashboard API endpoints with real database operations via TestClient.
"""

from datetime import datetime, timezone
from uuid import uuid4

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from backend.data.admin_models import (
    AdminAnnotation,
    AdminDocument,
    AdminToken,
    AnnotationHistory,
    ModelVersion,
    TrainingDataset,
    TrainingTask,
)
from backend.web.api.v1.admin.dashboard import create_dashboard_router
from backend.web.core.auth import validate_admin_token


def create_test_app(override_token_dep):
    """Create a FastAPI test application with dashboard router."""
    app = FastAPI()
    router = create_dashboard_router()
    app.include_router(router)

    # Override auth dependency
    app.dependency_overrides[validate_admin_token] = lambda: override_token_dep

    return app


class TestDashboardStatsEndpoint:
    """Tests for GET /admin/dashboard/stats endpoint."""

    def test_stats_empty_database(self, patched_session, admin_token):
        """Test stats endpoint with empty database."""
        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/stats")

        assert response.status_code == 200
        data = response.json()
        assert data["total_documents"] == 0
        assert data["annotation_complete"] == 0
        assert data["annotation_incomplete"] == 0
        assert data["pending"] == 0
        assert data["completeness_rate"] == 0.0

    def test_stats_with_pending_documents(self, patched_session, admin_token):
        """Test stats with pending documents."""
        session = patched_session

        # Create pending documents
        for i in range(3):
            doc = AdminDocument(
                document_id=uuid4(),
                admin_token=admin_token.token,
                filename=f"pending_{i}.pdf",
                file_size=1024,
                content_type="application/pdf",
                file_path=f"/uploads/pending_{i}.pdf",
                page_count=1,
                status="pending",
                upload_source="ui",
                category="invoice",
                created_at=datetime.now(timezone.utc),
                updated_at=datetime.now(timezone.utc),
            )
            session.add(doc)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/stats")

        assert response.status_code == 200
        data = response.json()
        assert data["total_documents"] == 3
        assert data["pending"] == 3

    def test_stats_with_complete_annotations(self, patched_session, admin_token):
        """Test stats with complete annotations."""
        session = patched_session

        # Create labeled document with complete annotations
        doc = AdminDocument(
            document_id=uuid4(),
            admin_token=admin_token.token,
            filename="complete.pdf",
            file_size=1024,
            content_type="application/pdf",
            file_path="/uploads/complete.pdf",
            page_count=1,
            status="labeled",
            upload_source="ui",
            category="invoice",
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        session.add(doc)
        session.commit()

        # Add identifier and payment annotations
        session.add(AdminAnnotation(
            annotation_id=uuid4(),
            document_id=doc.document_id,
            page_number=1,
            class_id=0,  # invoice_number
            class_name="invoice_number",
            x_center=0.5, y_center=0.1, width=0.2, height=0.05,
            bbox_x=400, bbox_y=80, bbox_width=160, bbox_height=40,
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        ))
        session.add(AdminAnnotation(
            annotation_id=uuid4(),
            document_id=doc.document_id,
            page_number=1,
            class_id=4,  # bankgiro
            class_name="bankgiro",
            x_center=0.5, y_center=0.2, width=0.2, height=0.05,
            bbox_x=400, bbox_y=160, bbox_width=160, bbox_height=40,
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        ))
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/stats")

        assert response.status_code == 200
        data = response.json()
        assert data["annotation_complete"] == 1
        assert data["completeness_rate"] == 100.0


class TestActiveModelEndpoint:
    """Tests for GET /admin/dashboard/active-model endpoint."""

    def test_active_model_none(self, patched_session, admin_token):
        """Test active-model endpoint with no active model."""
        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/active-model")

        assert response.status_code == 200
        data = response.json()
        assert data["model"] is None
        assert data["running_training"] is None

    def test_active_model_with_model(self, patched_session, admin_token, sample_dataset):
        """Test active-model endpoint with active model."""
        session = patched_session

        # Create training task
        task = TrainingTask(
            task_id=uuid4(),
            admin_token=admin_token.token,
            name="Test Task",
            status="completed",
            task_type="train",
            dataset_id=sample_dataset.dataset_id,
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        session.add(task)
        session.commit()

        # Create active model
        model = ModelVersion(
            version_id=uuid4(),
            version="1.0.0",
            name="Test Model",
            model_path="/models/test.pt",
            status="active",
            is_active=True,
            task_id=task.task_id,
            dataset_id=sample_dataset.dataset_id,
            metrics_mAP=0.90,
            metrics_precision=0.88,
            metrics_recall=0.85,
            document_count=100,
            file_size=50000000,
            activated_at=datetime.now(timezone.utc),
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        session.add(model)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/active-model")

        assert response.status_code == 200
        data = response.json()
        assert data["model"] is not None
        assert data["model"]["version"] == "1.0.0"
        assert data["model"]["name"] == "Test Model"
        assert data["model"]["metrics_mAP"] == 0.90

    def test_active_model_with_running_training(self, patched_session, admin_token, sample_dataset):
        """Test active-model endpoint with running training."""
        session = patched_session

        # Create running training task
        task = TrainingTask(
            task_id=uuid4(),
            admin_token=admin_token.token,
            name="Running Task",
            status="running",
            task_type="train",
            dataset_id=sample_dataset.dataset_id,
            started_at=datetime.now(timezone.utc),
            progress=50,
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        session.add(task)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/active-model")

        assert response.status_code == 200
        data = response.json()
        assert data["running_training"] is not None
        assert data["running_training"]["name"] == "Running Task"
        assert data["running_training"]["status"] == "running"
        assert data["running_training"]["progress"] == 50


class TestRecentActivityEndpoint:
    """Tests for GET /admin/dashboard/activity endpoint."""

    def test_activity_empty(self, patched_session, admin_token):
        """Test activity endpoint with no activities."""
        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/activity")

        assert response.status_code == 200
        data = response.json()
        assert data["activities"] == []

    def test_activity_with_uploads(self, patched_session, admin_token):
        """Test activity includes document uploads."""
        session = patched_session

        # Create documents
        for i in range(3):
            doc = AdminDocument(
                document_id=uuid4(),
                admin_token=admin_token.token,
                filename=f"activity_{i}.pdf",
                file_size=1024,
                content_type="application/pdf",
                file_path=f"/uploads/activity_{i}.pdf",
                page_count=1,
                status="pending",
                upload_source="ui",
                category="invoice",
                created_at=datetime.now(timezone.utc),
                updated_at=datetime.now(timezone.utc),
            )
            session.add(doc)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/activity")

        assert response.status_code == 200
        data = response.json()
        upload_activities = [a for a in data["activities"] if a["type"] == "document_uploaded"]
        assert len(upload_activities) == 3

    def test_activity_limit_parameter(self, patched_session, admin_token):
        """Test activity limit parameter."""
        session = patched_session

        # Create many documents
        for i in range(15):
            doc = AdminDocument(
                document_id=uuid4(),
                admin_token=admin_token.token,
                filename=f"limit_{i}.pdf",
                file_size=1024,
                content_type="application/pdf",
                file_path=f"/uploads/limit_{i}.pdf",
                page_count=1,
                status="pending",
                upload_source="ui",
                category="invoice",
                created_at=datetime.now(timezone.utc),
                updated_at=datetime.now(timezone.utc),
            )
            session.add(doc)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/activity?limit=5")

        assert response.status_code == 200
        data = response.json()
        assert len(data["activities"]) <= 5

    def test_activity_invalid_limit(self, patched_session, admin_token):
        """Test activity with invalid limit parameter."""
        app = create_test_app(admin_token.token)
        client = TestClient(app)

        # Limit too high
        response = client.get("/admin/dashboard/activity?limit=100")
        assert response.status_code == 422

        # Limit too low
        response = client.get("/admin/dashboard/activity?limit=0")
        assert response.status_code == 422

    def test_activity_with_training_completion(self, patched_session, admin_token, sample_dataset):
        """Test activity includes training completions."""
        session = patched_session

        # Create completed training task
        task = TrainingTask(
            task_id=uuid4(),
            admin_token=admin_token.token,
            name="Completed Task",
            status="completed",
            task_type="train",
            dataset_id=sample_dataset.dataset_id,
            metrics_mAP=0.95,
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        session.add(task)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/activity")

        assert response.status_code == 200
        data = response.json()
        training_activities = [a for a in data["activities"] if a["type"] == "training_completed"]
        assert len(training_activities) >= 1

    def test_activity_sorted_by_timestamp(self, patched_session, admin_token):
        """Test activities are sorted by timestamp descending."""
        session = patched_session

        # Create documents
        for i in range(5):
            doc = AdminDocument(
                document_id=uuid4(),
                admin_token=admin_token.token,
                filename=f"sorted_{i}.pdf",
                file_size=1024,
                content_type="application/pdf",
                file_path=f"/uploads/sorted_{i}.pdf",
                page_count=1,
                status="pending",
                upload_source="ui",
                category="invoice",
                created_at=datetime.now(timezone.utc),
                updated_at=datetime.now(timezone.utc),
            )
            session.add(doc)
        session.commit()

        app = create_test_app(admin_token.token)
        client = TestClient(app)

        response = client.get("/admin/dashboard/activity")

        assert response.status_code == 200
        data = response.json()
        timestamps = [a["timestamp"] for a in data["activities"]]
        assert timestamps == sorted(timestamps, reverse=True)
