#!/usr/bin/env python3
"""
Comprehensive test suite that tests ALL API endpoints in the codebase.
This ensures we have coverage for every single endpoint.
"""

import json
import time

import pytest
from loguru import logger


class TestAllEndpoints:
    """Comprehensive API test suite using Flask test client."""

    def test_all_auth_endpoints(self, authenticated_client):
        """Test ALL authentication endpoints."""
        logger.info("\n=== Testing ALL Authentication Endpoints ===")

        # Test endpoints
        endpoints = [
            ("GET", "/auth/check", None, 200),
            ("GET", "/auth/integrity-check", None, 200),
        ]

        for method, endpoint, data, expected_status in endpoints:
            if method == "GET":
                response = authenticated_client.get(endpoint)
            else:
                response = authenticated_client.post(
                    endpoint,
                    json=data,
                    content_type="application/json",
                )
            assert response.status_code == expected_status, (
                f"{endpoint} failed: {response.data}"
            )

        logger.info("✅ All Auth endpoints tested")

    def test_all_settings_endpoints(self, authenticated_client):
        """Test ALL settings endpoints."""
        logger.info("\n=== Testing ALL Settings Endpoints ===")

        # Basic GET endpoints
        get_endpoints = [
            "/settings/api",
            "/settings/api/categories",
            "/settings/api/types",
            "/settings/api/ui_elements",
            "/settings/api/available-models",
            "/settings/api/available-search-engines",
            "/settings/api/warnings",
            "/settings/api/ollama-status",
            "/settings/api/rate-limiting/status",
            "/settings/api/data-location",
        ]

        for endpoint in get_endpoints:
            response = authenticated_client.get(endpoint)
            assert response.status_code == 200, (
                f"{endpoint} failed: {response.data}"
            )

        # Test bulk get
        response = authenticated_client.get(
            "/settings/api/bulk?keys=llm.provider,llm.model"
        )
        assert response.status_code == 200, f"Bulk get failed: {response.data}"

        # Test setting CRUD (use an allow-listed prefix so the
        # namespace gate permits creation of this throwaway key).
        test_key = "llm.endpoint_test_value"
        test_value = {"value": "test_endpoint_123", "editable": True}

        # Create/Update
        response = authenticated_client.put(
            f"/settings/api/{test_key}",
            json=test_value,
            content_type="application/json",
        )
        assert response.status_code in [200, 201], (
            f"Create setting failed: {response.data}"
        )

        # Get specific setting
        data = json.loads(response.data)
        if isinstance(data, dict) and "setting" in data:
            actual_key = data["setting"].get("key", test_key)
        else:
            actual_key = test_key

        response = authenticated_client.get(f"/settings/api/{actual_key}")
        assert response.status_code == 200, (
            f"Get setting failed: {response.data}"
        )

        # Delete
        response = authenticated_client.delete(f"/settings/api/{actual_key}")
        assert response.status_code in [200, 204, 404], (
            f"Delete setting failed: {response.data}"
        )

        # Test rate limiting reset
        response = authenticated_client.post(
            "/settings/api/rate-limiting/engines/test/reset"
        )
        assert response.status_code in [200, 404], (
            f"Rate limit reset failed: {response.data}"
        )

        # Test cleanup
        response = authenticated_client.post(
            "/settings/api/rate-limiting/cleanup"
        )
        assert response.status_code == 200, (
            f"Rate limit cleanup failed: {response.data}"
        )

        logger.info("✅ All Settings endpoints tested")

    def test_all_research_endpoints(self, authenticated_client):
        """Test ALL research-related endpoints."""
        logger.info("\n=== Testing ALL Research Endpoints ===")

        # Set up logging.
        try:
            logger.level("MILESTONE", no=26, color="<magenta><bold>")
        except (TypeError, ValueError):
            pass  # Level already registered

        # Test history endpoint first
        response = authenticated_client.get("/history/api")
        assert response.status_code == 200, (
            f"History API failed: {response.data}"
        )

        # Start research via main endpoint
        research_data = {
            "query": "Test all endpoints comprehensive",
            "mode": "quick",
            "model_provider": "OLLAMA",
            "model": "llama2",
            "search_engine": "searxng",
            "max_results": 5,
            "time_period": "y",
            "iterations": 1,
            "questions_per_iteration": 2,
            "strategy": "rapid",
        }

        # Test /api/start_research endpoint
        response = authenticated_client.post(
            "/api/start_research",
            json=research_data,
            content_type="application/json",
        )
        assert response.status_code == 200, (
            f"Start research failed: {response.data}"
        )
        data = json.loads(response.data)
        assert "research_id" in data
        research_id = data["research_id"]

        # Give it a moment to start
        time.sleep(0.5)  # allow: unmarked-sleep

        # Test various research endpoints
        research_endpoints = [
            ("GET", f"/api/research/{research_id}", None, 200),
            ("GET", f"/api/research/{research_id}/status", None, 200),
            ("GET", f"/research/api/status/{research_id}", None, 200),
            ("GET", f"/history/status/{research_id}", None, 200),
            ("GET", f"/history/details/{research_id}", None, 200),
            ("GET", f"/history/log_count/{research_id}", None, 200),
        ]

        for method, endpoint, req_data, expected_status in research_endpoints:
            if method == "GET":
                response = authenticated_client.get(endpoint)
            else:
                response = authenticated_client.post(
                    endpoint,
                    json=req_data,
                    content_type="application/json",
                )
            # Some endpoints might return 404 if research is still initializing
            assert response.status_code in [expected_status, 404], (
                f"{endpoint} failed: {response.data}"
            )

        # Test research API routes
        response = authenticated_client.get(
            "/research/api/settings/current-config"
        )
        assert response.status_code == 200, (
            f"Current config failed: {response.data}"
        )

        response = authenticated_client.get("/research/api/config")
        assert response.status_code == 200, (
            f"Public config failed: {response.data}"
        )

        # Test Ollama checks
        response = authenticated_client.get("/research/api/check/ollama_status")
        assert response.status_code == 200, (
            f"Ollama status check failed: {response.data}"
        )

        # Terminate research
        response = authenticated_client.post(f"/api/terminate/{research_id}")
        assert response.status_code in [200, 400, 404], (
            f"Terminate research failed: {response.data}"
        )

        # Test alternate terminate endpoint
        response = authenticated_client.post(
            f"/research/api/terminate/{research_id}"
        )
        assert response.status_code in [200, 400, 404], (
            f"API terminate research failed: {response.data}"
        )

        logger.info("✅ All Research endpoints tested")

        return research_id

    def test_all_metrics_endpoints(self, authenticated_client):
        """Test ALL metrics endpoints."""
        logger.info("\n=== Testing ALL Metrics Endpoints ===")

        # Basic metrics endpoints
        metrics_endpoints = [
            "/metrics/api/metrics",
            "/metrics/api/metrics/enhanced",
            "/metrics/api/pricing",
            "/metrics/api/cost-analytics",
            "/metrics/api/star-reviews",
            "/metrics/api/rate-limiting",
            "/metrics/api/rate-limiting/current",
        ]

        for endpoint in metrics_endpoints:
            response = authenticated_client.get(endpoint)
            assert response.status_code == 200, (
                f"{endpoint} failed: {response.data}"
            )

        # Test specific model pricing
        response = authenticated_client.get(
            "/metrics/api/pricing/gpt-3.5-turbo"
        )
        assert response.status_code in [200, 404], (
            f"Model pricing failed: {response.data}"
        )

        # Test cost calculation
        cost_data = {
            "model_name": "gpt-3.5-turbo",
            "prompt_tokens": 1000,
            "completion_tokens": 500,
        }
        response = authenticated_client.post(
            "/metrics/api/cost-calculation",
            json=cost_data,
            content_type="application/json",
        )
        assert response.status_code == 200, (
            f"Cost calculation failed: {response.data}"
        )

        logger.info("✅ All Metrics endpoints tested")

    def test_all_benchmark_endpoints(self, authenticated_client):
        """Test ALL benchmark endpoints."""
        logger.info("\n=== Testing ALL Benchmark Endpoints ===")

        # Basic benchmark endpoints
        benchmark_endpoints = [
            "/benchmark/api/history",
            "/benchmark/api/configs",
            "/benchmark/api/running",
            "/benchmark/api/search-quality",
        ]

        for endpoint in benchmark_endpoints:
            response = authenticated_client.get(endpoint)
            assert response.status_code == 200, (
                f"{endpoint} failed: {response.data}"
            )

        # Test config validation
        test_config = {
            "name": "Test Benchmark Config",
            "queries": ["test query 1", "test query 2"],
            "models": ["gpt-3.5-turbo"],
            "search_engines": ["searxng"],
            "iterations": 1,
        }

        response = authenticated_client.post(
            "/benchmark/api/validate-config",
            json=test_config,
            content_type="application/json",
        )
        assert response.status_code == 200, (
            f"Validate config failed: {response.data}"
        )

        # Test simple benchmark start (but don't actually run it)
        simple_benchmark = {
            "query": "test benchmark",
            "models": ["gpt-3.5-turbo"],
            "search_engines": ["searxng"],
        }

        # Note: We won't actually start a benchmark as it's resource intensive
        # Just verify the endpoint exists
        response = authenticated_client.post(
            "/benchmark/api/start-simple",
            json=simple_benchmark,
            content_type="application/json",
        )
        # Accept 409 (conflict) if another benchmark is running
        assert response.status_code in [200, 409, 400], (
            f"Start simple benchmark status: {response.status_code}, {response.data}"
        )

        logger.info("✅ All Benchmark endpoints tested")

    def test_all_history_endpoints(self, authenticated_client):
        """Test ALL history endpoints."""
        logger.info("\n=== Testing ALL History Endpoints ===")

        # Basic history endpoint
        response = authenticated_client.get("/history/api")
        assert response.status_code == 200, (
            f"History API failed: {response.data}"
        )

        logger.info("✅ All History endpoints tested")

    @pytest.mark.requires_llm
    def test_all_api_v1_endpoints(self, authenticated_client):
        """Test ALL API v1 endpoints."""
        logger.info("\n=== Testing ALL API v1 Endpoints ===")

        # Health check (doesn't require auth)
        response = authenticated_client.get("/api/v1/health")
        assert response.status_code == 200, (
            f"Health check failed: {response.data}"
        )

        # API documentation
        response = authenticated_client.get("/api/v1/")
        assert response.status_code == 200, f"API docs failed: {response.data}"

        # Quick summary test
        summary_data = {"query": "What is machine learning?", "max_tokens": 100}
        response = authenticated_client.post(
            "/api/v1/quick_summary_test",
            json=summary_data,
            content_type="application/json",
        )
        # This endpoint might not be fully implemented
        assert response.status_code in [200, 404, 500], (
            f"Quick summary test status: {response.status_code}"
        )

        # Quick summary
        response = authenticated_client.post(
            "/api/v1/quick_summary",
            json=summary_data,
            content_type="application/json",
        )
        assert response.status_code in [200, 404, 500], (
            f"Quick summary status: {response.status_code}"
        )

        # Generate report
        report_data = {
            "query": "Test report generation",
            "research_type": "comprehensive",
        }
        response = authenticated_client.post(
            "/api/v1/generate_report",
            json=report_data,
            content_type="application/json",
        )
        assert response.status_code in [200, 404, 500], (
            f"Generate report status: {response.status_code}"
        )

        # Analyze documents
        doc_data = {
            "documents": ["test document content"],
            "query": "Summarize this document",
            "collection_name": "test_collection",
        }
        response = authenticated_client.post(
            "/api/v1/analyze_documents",
            json=doc_data,
            content_type="application/json",
        )
        assert response.status_code in [200, 404, 500], (
            f"Analyze documents status: {response.status_code}"
        )

        logger.info("✅ All API v1 endpoints tested")

    def test_miscellaneous_endpoints(self, authenticated_client):
        """Test miscellaneous endpoints not covered in other categories."""
        logger.info("\n=== Testing Miscellaneous Endpoints ===")

        # Test static file serving
        response = authenticated_client.get("/static/css/style.css")
        assert response.status_code in [200, 404], "Static file endpoint failed"

        # Test favicon
        response = authenticated_client.get("/favicon.ico")
        assert response.status_code in [200, 404], "Favicon endpoint failed"

        # Test pages that should exist
        page_endpoints = [
            "/",  # Home page
            "/history",  # History page
            "/settings",  # Settings page
            "/metrics/",  # Metrics dashboard
            "/benchmark/",  # Benchmark dashboard
        ]

        for endpoint in page_endpoints:
            response = authenticated_client.get(endpoint)
            assert response.status_code == 200, (
                f"Page {endpoint} failed with status {response.status_code}"
            )

        logger.info("✅ All miscellaneous endpoints tested")

    def test_error_handling(self, authenticated_client):
        """Test error handling for invalid endpoints and methods."""
        logger.info("\n=== Testing Error Handling ===")

        # Test non-existent endpoint
        response = authenticated_client.get("/api/does-not-exist")
        assert response.status_code == 404, (
            f"Non-existent endpoint should return 404, got {response.status_code}"
        )

        # Test wrong method
        response = authenticated_client.delete("/auth/check")
        assert response.status_code in [404, 405], (
            f"Wrong method should return 404/405, got {response.status_code}"
        )

        # Test invalid JSON
        response = authenticated_client.post(
            "/api/start_research",
            data="invalid json",
            content_type="application/json",
        )
        assert response.status_code in [400, 500], (
            f"Invalid JSON should return 400/500, got {response.status_code}"
        )

        logger.info("✅ Error handling tested")
