from datetime import datetime, timezone
from unittest.mock import MagicMock

import pytest
from fastapi.testclient import TestClient

from app.main import app


@pytest.fixture
def client(monkeypatch):
    # Ensure services can be patched per test
    return TestClient(app)


def test_get_credit_summary(client, monkeypatch):
    mock_summary = {
        "userId": "user-123",
        "credits": 900,
        "totalCreditsUsed": 100,
        "plan": "free",
        "lastResetDate": datetime(2024, 1, 1, tzinfo=timezone.utc),
        "nextResetDate": datetime(2024, 2, 1, tzinfo=timezone.utc),
    }

    monkeypatch.setattr(
        "app.services.credits.get_credit_summary",
        lambda user_id: mock_summary,
    )

    response = client.get("/api/v1/credits", headers={"X-User-ID": "user-123"})
    assert response.status_code == 200
    data = response.json()
    assert data["credits"] == 900
    assert data["userId"] == "user-123"


def test_get_credit_logs(client, monkeypatch):
    mock_logs = [
        {
            "id": "log1",
            "amount": -50,
            "type": "firewall",
            "description": "Firewall check",
            "timestamp": datetime(2024, 1, 2, tzinfo=timezone.utc),
        }
    ]
    monkeypatch.setattr(
        "app.services.credits.get_credit_logs",
        lambda user_id, limit=50: mock_logs,
    )

    response = client.get("/api/v1/credits/logs", headers={"X-User-ID": "user-123"})
    assert response.status_code == 200
    logs = response.json()
    assert len(logs) == 1
    assert logs[0]["id"] == "log1"




def test_list_api_keys(client, monkeypatch):
    mock_list = [
        {"id": "key1", "name": "Key", "description": "Test", "createdAt": datetime(2024, 1, 1, tzinfo=timezone.utc), "lastUsed": None, "usageCount": 5, "active": True}
    ]
    monkeypatch.setattr("app.services.api_keys.list_api_keys", lambda user_id: mock_list)

    response = client.get("/api/v1/api-keys", headers={"X-User-ID": "user-123"})
    assert response.status_code == 200
    data = response.json()
    assert data[0]["id"] == "key1"


def test_create_api_key(client, monkeypatch):
    created_at = datetime(2024, 1, 1, tzinfo=timezone.utc)
    mock_generate = MagicMock(return_value={
        "key": "tano_mock",
        "record": {
            "id": "key1",
            "name": "My Key",
            "description": "Test",
            "createdAt": created_at,
            "lastUsed": None,
            "usageCount": 0,
            "active": True,
        },
    })
    monkeypatch.setattr("app.services.api_keys.generate_api_key", mock_generate)

    payload = {"name": "My Key", "description": "Test"}
    response = client.post(
        "/api/v1/api-keys",
        json=payload,
        headers={"X-User-ID": "user-123"},
    )
    assert response.status_code == 201
    data = response.json()
    assert data["key"] == "tano_mock"
    assert data["record"]["id"] == "key1"
    mock_generate.assert_called_once()


def test_toggle_api_key(client, monkeypatch):
    mock_toggle = MagicMock()
    monkeypatch.setattr("app.services.api_keys.toggle_api_key", mock_toggle)

    response = client.post(
        "/api/v1/api-keys/toggle",
        json={"keyId": "key1", "active": False},
        headers={"X-User-ID": "user-123"},
    )
    assert response.status_code == 204
    mock_toggle.assert_called_once_with("user-123", "key1", False)


def test_revoke_api_key(client, monkeypatch):
    mock_revoke = MagicMock()
    monkeypatch.setattr("app.services.api_keys.revoke_api_key", mock_revoke)

    response = client.post(
        "/api/v1/api-keys/revoke",
        json={"keyId": "key1"},
        headers={"X-User-ID": "user-123"},
    )
    assert response.status_code == 204
    mock_revoke.assert_called_once_with("user-123", "key1")


def test_firewall_check_endpoint(client, monkeypatch):
    mock_result = {
        'overallSafe': True,
        'checks': [
            {'id': 'harmfulness', 'name': 'Harmfulness', 'safe': True, 'details': 'All good'}
        ],
        'filtered': False,
        'creditsUsed': 2,
        'timestamp': datetime(2024, 1, 1, tzinfo=timezone.utc),
    }
    monkeypatch.setattr(
        'app.api.v1.endpoints.firewall.run_firewall_check',
        lambda payload, user_id, source=None: mock_result,
    )

    response = client.post(
        '/api/v1/firewall/check',
        json={'user_input': 'hello', 'securityChecks': ['harmfulness']},
        headers={'X-User-ID': 'user-123'},
    )
    assert response.status_code == 200
    body = response.json()
    assert body['overallSafe'] is True


def test_pii_redaction_endpoint(client, monkeypatch):
    from app.models.pii import PiiRedactionResponse

    async def fake_redact(payload, user_id, source=None, api_key=None):
        return PiiRedactionResponse(
            anonymized_text='[REDACTED]',
            entities={'PERSON': ['Alice']},
            credits_used=1,
            timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc),
        )

    monkeypatch.setattr('app.api.v1.endpoints.pii.redact_text', fake_redact)

    response = client.post(
        '/api/v1/pii-redaction',
        json={'text': 'Alice lives in Paris'},
        headers={'X-User-ID': 'user-123'},
    )

    assert response.status_code == 200
    body = response.json()
    assert body['anonymized_text'] == '[REDACTED]'
    assert body['creditsUsed'] == 1


def test_scan_endpoint(monkeypatch):
    client = TestClient(app)

    from app.models.scan import ScanResult

    fake_result = ScanResult(
        issues=[],
        firewall_results=[],
        timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc),
        credits_used=100,
    )
    monkeypatch.setattr('app.api.v1.endpoints.scan.execute_scan', lambda payload, user_id: fake_result)

    response = client.post(
        '/api/v1/scan',
        json={'prompt': 'hello', 'categories': ['harmfulness']},
        headers={'X-User-ID': 'user-123'},
    )
    assert response.status_code == 200
    body = response.json()
    assert body['creditsUsed'] == 100
