from models import Annotation, Frame, Mask, ProcessingTask, Project


def test_project_crud_and_frames(client, monkeypatch):
    monkeypatch.setattr("routers.projects.get_presigned_url", lambda key, expires=3600: f"http://storage/{key}")

    created = client.post("/api/projects", json={
        "name": "Demo",
        "description": "desc",
        "thumbnail_url": "thumb.jpg",
        "parse_fps": 12,
    })
    assert created.status_code == 201
    project_id = created.json()["id"]

    frame = client.post(f"/api/projects/{project_id}/frames", json={
        "project_id": project_id,
        "frame_index": 0,
        "image_url": "frames/0.jpg",
        "width": 640,
        "height": 360,
    })
    assert frame.status_code == 201
    frame_id = frame.json()["id"]

    listing = client.get("/api/projects")
    assert listing.status_code == 200
    assert listing.json()[0]["frame_count"] == 1
    assert listing.json()[0]["thumbnail_url"] == "http://storage/thumb.jpg"

    frames = client.get(f"/api/projects/{project_id}/frames")
    assert frames.status_code == 200
    assert frames.json()[0]["image_url"] == "http://storage/frames/0.jpg"

    single_frame = client.get(f"/api/projects/{project_id}/frames/{frame_id}")
    assert single_frame.status_code == 200
    assert single_frame.json()["frame_index"] == 0

    updated = client.patch(f"/api/projects/{project_id}", json={"name": "Renamed", "status": "ready"})
    assert updated.status_code == 200
    assert updated.json()["name"] == "Renamed"
    assert updated.json()["status"] == "ready"

    deleted = client.delete(f"/api/projects/{project_id}")
    assert deleted.status_code == 204
    assert client.get(f"/api/projects/{project_id}").status_code == 404


def test_delete_project_cascades_related_records(client, db_session):
    created = client.post("/api/projects", json={"name": "Cascade Delete"})
    assert created.status_code == 201
    project_id = created.json()["id"]

    frame = client.post(f"/api/projects/{project_id}/frames", json={
        "project_id": project_id,
        "frame_index": 0,
        "image_url": "frames/0.jpg",
        "width": 640,
        "height": 360,
    })
    assert frame.status_code == 201
    frame_id = frame.json()["id"]

    annotation = client.post("/api/ai/annotate", json={
        "project_id": project_id,
        "frame_id": frame_id,
        "mask_data": {"polygons": [[[0.1, 0.1], [0.2, 0.1], [0.2, 0.2]]]},
    })
    assert annotation.status_code == 201
    annotation_id = annotation.json()["id"]

    db_session.add(Mask(annotation_id=annotation_id, mask_url="masks/1.png"))
    db_session.add(ProcessingTask(task_type="parse_video", project_id=project_id, status="queued"))
    db_session.commit()

    deleted = client.delete(f"/api/projects/{project_id}")
    assert deleted.status_code == 204
    assert db_session.query(Project).filter(Project.id == project_id).count() == 0
    assert db_session.query(Frame).filter(Frame.project_id == project_id).count() == 0
    assert db_session.query(Annotation).filter(Annotation.project_id == project_id).count() == 0
    assert db_session.query(Mask).count() == 0
    assert db_session.query(ProcessingTask).filter(ProcessingTask.project_id == project_id).count() == 0


def test_project_and_frame_404s(client):
    assert client.get("/api/projects/999").status_code == 404
    assert client.patch("/api/projects/999", json={"name": "x"}).status_code == 404
    assert client.delete("/api/projects/999").status_code == 404
    assert client.post("/api/projects/999/frames", json={
        "project_id": 999,
        "frame_index": 0,
        "image_url": "missing.jpg",
    }).status_code == 404
    assert client.get("/api/projects/999/frames").status_code == 404
    assert client.get("/api/projects/999/frames/1").status_code == 404
