"""API integration tests."""

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

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


# Test database
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():
    """Override database dependency for tests."""
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


app.dependency_overrides[get_db] = override_get_db


@pytest.fixture(autouse=True)
def setup_db():
    """Setup test database before each test."""
    Base.metadata.create_all(bind=engine)
    yield
    Base.metadata.drop_all(bind=engine)


@pytest.fixture
def client():
    """Test client fixture."""
    return TestClient(app)


@pytest.fixture
def auth_headers(client):
    """Create user and return auth headers."""
    # Register user
    client.post("/auth/register", json={
        "email": "test@example.com",
        "username": "testuser",
        "password": "testpass123"
    })

    # Login
    response = client.post("/auth/login", data={
        "username": "testuser",
        "password": "testpass123"
    })
    token = response.json()["access_token"]
    return {"Authorization": f"Bearer {token}"}


class TestHealth:
    """Health check tests."""

    def test_health_check(self, client):
        """Test health endpoint."""
        response = client.get("/health")
        assert response.status_code == 200
        assert response.json()["status"] == "healthy"

    def test_root(self, client):
        """Test root endpoint."""
        response = client.get("/")
        assert response.status_code == 200
        assert "app" in response.json()


class TestAuth:
    """Authentication tests."""

    def test_register(self, client):
        """Test user registration."""
        response = client.post("/auth/register", json={
            "email": "new@example.com",
            "username": "newuser",
            "password": "password123"
        })
        assert response.status_code == 201
        assert response.json()["username"] == "newuser"

    def test_register_duplicate_email(self, client):
        """Test duplicate email registration."""
        user_data = {
            "email": "dup@example.com",
            "username": "user1",
            "password": "password123"
        }
        client.post("/auth/register", json=user_data)

        user_data["username"] = "user2"
        response = client.post("/auth/register", json=user_data)
        assert response.status_code == 400

    def test_login(self, client):
        """Test user login."""
        # Register first
        client.post("/auth/register", json={
            "email": "login@example.com",
            "username": "loginuser",
            "password": "password123"
        })

        # Login
        response = client.post("/auth/login", data={
            "username": "loginuser",
            "password": "password123"
        })
        assert response.status_code == 200
        assert "access_token" in response.json()

    def test_login_wrong_password(self, client):
        """Test login with wrong password."""
        client.post("/auth/register", json={
            "email": "wrong@example.com",
            "username": "wronguser",
            "password": "password123"
        })

        response = client.post("/auth/login", data={
            "username": "wronguser",
            "password": "wrongpassword"
        })
        assert response.status_code == 401

    def test_get_me(self, client, auth_headers):
        """Test get current user."""
        response = client.get("/auth/me", headers=auth_headers)
        assert response.status_code == 200
        assert response.json()["username"] == "testuser"


class TestTasks:
    """Task CRUD tests."""

    def test_create_task(self, client, auth_headers):
        """Test task creation."""
        response = client.post("/tasks", json={
            "title": "Test Task",
            "description": "Test description",
            "priority": "high"
        }, headers=auth_headers)
        assert response.status_code == 201
        assert response.json()["title"] == "Test Task"

    def test_list_tasks(self, client, auth_headers):
        """Test listing tasks."""
        # Create a task first
        client.post("/tasks", json={"title": "Task 1"}, headers=auth_headers)

        response = client.get("/tasks", headers=auth_headers)
        assert response.status_code == 200
        assert response.json()["total"] >= 1

    def test_get_task(self, client, auth_headers):
        """Test getting a specific task."""
        # Create a task
        create_response = client.post("/tasks", json={"title": "Get Task"}, headers=auth_headers)
        task_id = create_response.json()["id"]

        response = client.get(f"/tasks/{task_id}", headers=auth_headers)
        assert response.status_code == 200
        assert response.json()["title"] == "Get Task"

    def test_update_task(self, client, auth_headers):
        """Test updating a task."""
        # Create a task
        create_response = client.post("/tasks", json={"title": "Update Task"}, headers=auth_headers)
        task_id = create_response.json()["id"]

        # Update
        response = client.put(f"/tasks/{task_id}", json={
            "title": "Updated Task",
            "status": "completed"
        }, headers=auth_headers)
        assert response.status_code == 200
        assert response.json()["title"] == "Updated Task"
        assert response.json()["status"] == "completed"

    def test_delete_task(self, client, auth_headers):
        """Test deleting a task."""
        # Create a task
        create_response = client.post("/tasks", json={"title": "Delete Task"}, headers=auth_headers)
        task_id = create_response.json()["id"]

        # Delete
        response = client.delete(f"/tasks/{task_id}", headers=auth_headers)
        assert response.status_code == 204

        # Verify deleted
        response = client.get(f"/tasks/{task_id}", headers=auth_headers)
        assert response.status_code == 404

    def test_task_not_found(self, client, auth_headers):
        """Test getting non-existent task."""
        response = client.get("/tasks/99999", headers=auth_headers)
        assert response.status_code == 404

    def test_unauthorized_access(self, client):
        """Test accessing tasks without auth."""
        response = client.get("/tasks")
        assert response.status_code == 401
