import os
from typing import Generator

import sentry_sdk
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

os.environ.setdefault("WEB_SENTINEL_POSTGRES_URL", "sqlite:///./test_admin_monitoring.db")
os.environ.setdefault("WEB_SENTINEL_ADMIN_JWT_SECRET", "test-secret")

from admin.backend.app.database import get_session
from admin.backend.app.main import create_app
from admin.backend.app.models import Base
from admin.backend.app.models.admin_user import AdminUser
from admin.backend.app.security import hash_password

engine = create_engine(os.environ["WEB_SENTINEL_POSTGRES_URL"], future=True)
TestingSession = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)

Base.metadata.create_all(bind=engine)


def override_session() -> Generator:
    db = TestingSession()
    try:
        yield db
    finally:
        db.close()


app = create_app()
app.dependency_overrides[get_session] = override_session
client = TestClient(app)


def setup_module() -> None:
    Base.metadata.create_all(bind=engine)
    with TestingSession() as session:
        session.query(AdminUser).delete()
        session.add(
            AdminUser(
                email="sysop@web-sentinel.com",
                hashed_password=hash_password("secret"),
                role="super-admin",
            )
        )
        session.commit()


def teardown_module() -> None:
    Base.metadata.drop_all(bind=engine)


def _login() -> str:
    response = client.post(
        "/api/v1/auth/login",
        data={"username": "sysop@web-sentinel.com", "password": "secret"},
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )
    assert response.status_code == 200
    return response.json()["access_token"]


def test_monitoring_config_defaults_and_metrics():
    token = _login()
    response = client.get(
        "/api/v1/monitoring/config",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 200
    config = response.json()
    assert config["prometheus_enabled"] is False
    assert config["sentry_events"] == []

    metrics = client.get(
        "/api/v1/monitoring/metrics",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert metrics.status_code == 200
    metrics_payload = metrics.json()
    assert "requests_total" in metrics_payload
    assert "database_size_mb" in metrics_payload

    health = client.get(
        "/api/v1/monitoring/health",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert health.status_code == 200
    health_payload = health.json()
    assert health_payload["status"] == "ok"


def test_monitoring_config_update_and_sentry_test():
    token = _login()
    payload = {
        "sentry_dsn": "https://sentry.example.com/123",
        "sentry_environment": "staging",
        "prometheus_enabled": True,
        "prometheus_scrape_interval": 30,
    }
    response = client.put(
        "/api/v1/monitoring/config",
        json=payload,
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 200
    assert response.json()["prometheus_enabled"] is True

    sent_events: list[str] = []

    def _mock_capture_message(message: str, level: str = "info"):
        sent_events.append(message)
        return "fake-event-id"

    original_capture = sentry_sdk.capture_message
    sentry_sdk.capture_message = _mock_capture_message  # type: ignore[assignment]
    try:
        response = client.post(
            "/api/v1/monitoring/sentry/test",
            json={"message": "ping"},
            headers={"Authorization": f"Bearer {token}"},
        )
    finally:
        sentry_sdk.capture_message = original_capture  # type: ignore[assignment]

    assert response.status_code == 200
    data = response.json()
    assert data["last_ping"] is not None
    assert data["sentry_events"][-1]["event_id"] == "fake-event-id"
    assert sent_events == ["ping"]


def test_monitoring_config_rejects_invalid_dsn():
    token = _login()
    response = client.put(
        "/api/v1/monitoring/config",
        json={"sentry_dsn": "http://insecure", "prometheus_enabled": False},
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 422
