from datetime import date, timedelta

from app.models.enums import NotificationType, PolicyStatus
from app.services.notification_service import NotificationService


def test_generate_expiring_today_notification(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today()
    db.commit()

    result = client.post("/api/v1/notifications/generate", headers=auth_headers)
    assert result.status_code == 200
    assert result.json()["created"] >= 1

    listing = client.get("/api/v1/notifications", headers=auth_headers)
    assert listing.status_code == 200
    body = listing.json()
    assert body["unread_count"] >= 1
    types = {item["notification_type"] for item in body["items"]}
    assert NotificationType.EXPIRING_TODAY.value in types


def test_generate_expiring_tomorrow_notification(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today() + timedelta(days=1)
    db.commit()

    client.post("/api/v1/notifications/generate", headers=auth_headers)
    listing = client.get("/api/v1/notifications", headers=auth_headers)
    types = {item["notification_type"] for item in listing.json()["items"]}
    assert NotificationType.EXPIRING_TOMORROW.value in types


def test_generate_expiring_next_week_notification(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today() + timedelta(days=5)
    db.commit()

    client.post("/api/v1/notifications/generate", headers=auth_headers)
    listing = client.get("/api/v1/notifications", headers=auth_headers)
    types = {item["notification_type"] for item in listing.json()["items"]}
    assert NotificationType.EXPIRING_NEXT_WEEK.value in types


def test_notification_idempotent(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today()
    db.commit()

    first = client.post("/api/v1/notifications/generate", headers=auth_headers).json()
    second = client.post("/api/v1/notifications/generate", headers=auth_headers).json()
    assert first["created"] >= 1
    assert second["created"] == 0


def test_skip_renewed_policies(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today()
    policy.status = PolicyStatus.RENEWED
    db.commit()

    result = client.post("/api/v1/notifications/generate", headers=auth_headers).json()
    assert result["created"] == 0


def test_user_preferences_disable_notification(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today()
    db.commit()

    client.put(
        "/api/v1/notifications/preferences",
        headers=auth_headers,
        json={"notify_expiring_today": False},
    )
    result = client.post("/api/v1/notifications/generate", headers=auth_headers).json()
    assert result["created"] == 0


def test_mark_read_and_unread_count(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.policy_end_date = date.today()
    db.commit()
    client.post("/api/v1/notifications/generate", headers=auth_headers)

    listing = client.get("/api/v1/notifications", headers=auth_headers).json()
    notification_id = listing["items"][0]["id"]
    assert listing["unread_count"] >= 1

    client.patch(f"/api/v1/notifications/{notification_id}/read", headers=auth_headers)
    count = client.get("/api/v1/notifications/unread-count", headers=auth_headers).json()
    assert count["unread_count"] == listing["unread_count"] - 1


def test_register_device_token(client, auth_headers):
    response = client.post(
        "/api/v1/notifications/devices",
        headers=auth_headers,
        json={"platform": "android", "token": "fcm-test-token-abc123456789", "device_name": "Pixel"},
    )
    assert response.status_code == 200
    assert response.json()["platform"] == "android"

    removed = client.delete(
        "/api/v1/notifications/devices",
        headers=auth_headers,
        params={"token": "fcm-test-token-abc123456789"},
    )
    assert removed.status_code == 200
    assert removed.json()["removed"] is True


def test_notifications_require_auth(client):
    assert client.get("/api/v1/notifications").status_code == 401


def test_notification_service_type_mapping():
    svc = NotificationService(db=None)
    assert svc._type_for_days_left(0) == NotificationType.EXPIRING_TODAY
    assert svc._type_for_days_left(1) == NotificationType.EXPIRING_TOMORROW
    assert svc._type_for_days_left(5) == NotificationType.EXPIRING_NEXT_WEEK
    assert svc._type_for_days_left(10) is None
