import pytest
from unittest.mock import MagicMock
import pandas as pd
from datetime import timedelta
from fabra.core import FeatureStore, Entity, FeatureRegistry, entity, feature
from fabra.scheduler import Scheduler
from fastapi.testclient import TestClient


# 4.1 Missing Tests - Core Module
def test_feature_store_repr_html() -> None:
    store = FeatureStore()

    @entity(store)
    class User:
        user_id: str

    @feature(User, refresh="1h")
    def user_feature(i: str) -> int:
        return 1

    html = store._repr_html_()
    assert "User" in html
    assert "user_feature" in html
    assert "Compass" not in html  # Should be "Fabra"


def test_entity_repr_html() -> None:
    ent = Entity(name="User", id_column="uid", description="A user")
    html = ent._repr_html_()
    assert "User" in html
    assert "uid" in html


def test_get_features_empty() -> None:
    reg = FeatureRegistry()
    assert reg.get_features_for_entity("NonExistent") == []


@pytest.mark.asyncio
async def test_get_training_data_missing_timestamp() -> None:
    store = FeatureStore()
    df = pd.DataFrame({"id": ["u1"]})  # Missing timestamp

    # Mock offline store
    store.offline_store = MagicMock()

    # Should raise error or handle it?
    # Current code assumes timestamp presence for SQL features join logic
    # But let's verify if Python features work without it if features list is empty
    result = await store.get_training_data(df, features=[])
    assert len(result) == 1


# 4.2 Missing Tests - CLI Module (Mocked)
# (Skipping complex CLI mocks here to focus on logic, tested via existing test_cli.py)


# 4.3 Missing Tests - Server Module
def test_metrics_endpoint() -> None:
    from fabra.server import create_app

    store = FeatureStore()
    app = create_app(store)
    client = TestClient(app)

    response = client.get("/metrics")
    assert response.status_code == 200
    assert "fabra_request_count" in response.text


def test_features_non_existent_entity() -> None:
    from fabra.server import create_app

    store = FeatureStore()
    # Mock auth
    from fabra.server import get_api_key

    app = create_app(store)
    app.dependency_overrides[get_api_key] = lambda: "dev-mode"

    client = TestClient(app)
    response = client.post(
        "/v1/features",
        json={"entity_name": "Ghost", "entity_id": "123", "features": ["f1"]},
    )
    # Online store returns empty dict for valid request even if entity doesn't exist?
    # No, it should probably work but return nothing found.
    assert response.status_code == 200
    assert response.json() == {}


# 4.4 Missing Tests - Scheduler
def test_scheduler_deduplication() -> None:
    sched = Scheduler()
    sched.start()

    try:
        job_id = "job_1"
        func = MagicMock()

        sched.schedule_job(func, interval_seconds=10, job_id=job_id)
        sched.schedule_job(func, interval_seconds=10, job_id=job_id)

        # Check jobs in internal scheduler
        jobs = sched.scheduler.get_jobs()
        assert len([j for j in jobs if j.id == job_id]) == 1
    finally:
        sched.shutdown()


# 4.6 Edge Case Tests
def test_parse_timedelta_zero() -> None:
    from fabra.core import _parse_timedelta

    assert _parse_timedelta("0s") == timedelta(seconds=0)
    assert _parse_timedelta("0m") == timedelta(minutes=0)


def test_feature_decorator_no_entity() -> None:
    # Should raise error if not passed valid entity type
    # But type checker catches this mostly.
    pass
