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

from ..main import app
from ..db import Base, get_db

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


def override_get_db():
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


app.dependency_overrides[get_db] = override_get_db


@pytest.fixture(autouse=True)
def setup_database():
    Base.metadata.create_all(bind=engine)
    yield
    Base.metadata.drop_all(bind=engine)


client = TestClient(app)


class TestHealthEndpoint:
    def test_health_check(self):
        response = client.get("/health")
        assert response.status_code == 200
        assert response.json() == {"status": "ok"}


class TestTasksEndpoint:
    def test_create_task(self):
        task_data = {
            "title": "Test Task",
            "description": "Test Description",
            "date": "2026-02-02",
            "priority": "medium",
        }
        response = client.post("/tasks", json=task_data)
        assert response.status_code == 201
        data = response.json()
        assert data["title"] == "Test Task"
        assert data["is_done"] == False
        assert "id" in data

    def test_create_task_validation_error(self):
        task_data = {
            "title": "",
            "date": "2026-02-02",
        }
        response = client.post("/tasks", json=task_data)
        assert response.status_code == 422

    def test_get_tasks_by_date(self):
        task_data = {
            "title": "Test Task",
            "date": "2026-02-02",
            "priority": "high",
        }
        client.post("/tasks", json=task_data)

        response = client.get("/tasks?date=2026-02-02")
        assert response.status_code == 200
        data = response.json()
        assert len(data) == 1
        assert data[0]["title"] == "Test Task"

    def test_get_tasks_filter_active(self):
        client.post(
            "/tasks",
            json={"title": "Active Task", "date": "2026-02-02", "priority": "low"},
        )
        create_response = client.post(
            "/tasks",
            json={"title": "Done Task", "date": "2026-02-02", "priority": "low"},
        )
        task_id = create_response.json()["id"]
        client.patch(f"/tasks/{task_id}/toggle")

        response = client.get("/tasks?date=2026-02-02&status=active")
        assert response.status_code == 200
        data = response.json()
        assert len(data) == 1
        assert data[0]["title"] == "Active Task"

    def test_get_task_not_found(self):
        response = client.get("/tasks/nonexistent-id")
        assert response.status_code == 404

    def test_update_task(self):
        create_response = client.post(
            "/tasks",
            json={"title": "Original", "date": "2026-02-02", "priority": "low"},
        )
        task_id = create_response.json()["id"]

        response = client.put(
            f"/tasks/{task_id}",
            json={"title": "Updated"},
        )
        assert response.status_code == 200
        assert response.json()["title"] == "Updated"

    def test_delete_task(self):
        create_response = client.post(
            "/tasks",
            json={"title": "To Delete", "date": "2026-02-02", "priority": "low"},
        )
        task_id = create_response.json()["id"]

        response = client.delete(f"/tasks/{task_id}")
        assert response.status_code == 204

        get_response = client.get(f"/tasks/{task_id}")
        assert get_response.status_code == 404

    def test_delete_task_not_found(self):
        response = client.delete("/tasks/nonexistent-id")
        assert response.status_code == 404

    def test_toggle_task_status(self):
        create_response = client.post(
            "/tasks",
            json={"title": "Toggle Me", "date": "2026-02-02", "priority": "medium"},
        )
        task_id = create_response.json()["id"]
        assert create_response.json()["is_done"] == False

        response = client.patch(f"/tasks/{task_id}/toggle")
        assert response.status_code == 200
        assert response.json()["is_done"] == True

        response = client.patch(f"/tasks/{task_id}/toggle")
        assert response.json()["is_done"] == False

    def test_reschedule_task(self):
        create_response = client.post(
            "/tasks",
            json={"title": "Reschedule Me", "date": "2026-02-02", "priority": "high"},
        )
        task_id = create_response.json()["id"]

        response = client.post(
            f"/tasks/{task_id}/reschedule",
            json={"target_date": "2026-02-03"},
        )
        assert response.status_code == 200
        assert response.json()["date"] == "2026-02-03"
