"""High priority photo API tests."""

from __future__ import annotations

from datetime import date
from typing import TYPE_CHECKING

import pytest
from fastapi.testclient import TestClient

if TYPE_CHECKING:
    from sqlalchemy.orm import Session
    from backend.db.models import Photo, Person, Face, User


class TestPhotoSearch:
    """Test photo search endpoints."""

    def test_search_photos_by_name_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        test_person: "Person",
        test_face: "Face",
        test_db_session: "Session",
    ):
        """Verify search by person name works."""
        # Link face to person
        test_face.person_id = test_person.id
        test_db_session.commit()
        test_db_session.refresh(test_face)
        
        # Verify the link was created
        assert test_face.person_id == test_person.id
        assert test_face.photo_id == test_photo.id
        
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "name", "person_name": "John"},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data
        assert "total" in data
        # With test_person.first_name="John" and face linked, we should find results
        assert len(data["items"]) > 0
        # Verify the photo is in the results
        photo_ids = [item["id"] for item in data["items"]]
        assert test_photo.id in photo_ids

    def test_search_photos_by_name_without_person_name(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 400 when person_name missing."""
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "name"},
        )
        
        assert response.status_code == 400
        assert "person_name is required" in response.json()["detail"]

    def test_search_photos_by_name_with_pagination(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        test_person: "Person",
        test_face: "Face",
        test_db_session: "Session",
    ):
        """Verify pagination works correctly."""
        test_face.person_id = test_person.id
        test_db_session.commit()
        
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={
                "search_type": "name",
                "person_name": "John Doe",
                "page": 1,
                "page_size": 10,
            },
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["page"] == 1
        assert data["page_size"] == 10
        assert len(data["items"]) <= 10

    def test_search_photos_by_date_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
    ):
        """Verify date range search."""
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={
                "search_type": "date",
                "date_from": "2024-01-01",
                "date_to": "2024-12-31",
            },
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data

    def test_search_photos_by_date_without_dates(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 400 when both dates missing."""
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "date"},
        )
        
        assert response.status_code == 400
        assert "date_from or date_to is required" in response.json()["detail"]

    def test_search_photos_by_tags_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        test_db_session: "Session",
    ):
        """Verify tag search works."""
        from backend.db.models import Tag, PhotoTagLinkage
        
        # Create tag and link to photo
        tag = Tag(tag_name="test-tag")
        test_db_session.add(tag)
        test_db_session.flush()
        
        photo_tag = PhotoTagLinkage(photo_id=test_photo.id, tag_id=tag.id)
        test_db_session.add(photo_tag)
        test_db_session.commit()
        
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "tags", "tag_names": "test-tag"},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data

    def test_search_photos_by_tags_without_tags(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 400 when tag_names missing."""
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "tags"},
        )
        
        assert response.status_code == 400
        assert "tag_names is required" in response.json()["detail"]

    def test_search_photos_no_faces(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
    ):
        """Verify photos without faces search."""
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "no_faces"},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data

    def test_search_photos_returns_favorite_status(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        admin_user: "User",
        test_db_session: "Session",
    ):
        """Verify is_favorite field in results."""
        from backend.db.models import PhotoFavorite
        
        # Add favorite
        favorite = PhotoFavorite(photo_id=test_photo.id, username=admin_user.username)
        test_db_session.add(favorite)
        test_db_session.commit()
        
        response = test_client.get(
            "/api/v1/photos",
            headers=auth_headers,
            params={"search_type": "date", "date_from": "2024-01-01"},
        )
        
        assert response.status_code == 200
        data = response.json()
        if len(data["items"]) > 0:
            # Check if our photo is in results and has is_favorite
            photo_ids = [item["id"] for item in data["items"]]
            if test_photo.id in photo_ids:
                photo_item = next(item for item in data["items"] if item["id"] == test_photo.id)
                assert "is_favorite" in photo_item


class TestPhotoFavorites:
    """Test photo favorites endpoints."""

    def test_toggle_favorite_add(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        admin_user: "User",
        test_db_session: "Session",
    ):
        """Verify adding favorite."""
        response = test_client.post(
            f"/api/v1/photos/{test_photo.id}/toggle-favorite",
            headers=auth_headers,
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["is_favorite"] is True
        
        # Verify in database
        from backend.db.models import PhotoFavorite
        favorite = test_db_session.query(PhotoFavorite).filter(
            PhotoFavorite.photo_id == test_photo.id,
            PhotoFavorite.username == admin_user.username,
        ).first()
        assert favorite is not None

    def test_toggle_favorite_remove(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        admin_user: "User",
        test_db_session: "Session",
    ):
        """Verify removing favorite."""
        from backend.db.models import PhotoFavorite
        
        # Add favorite first
        favorite = PhotoFavorite(photo_id=test_photo.id, username=admin_user.username)
        test_db_session.add(favorite)
        test_db_session.commit()
        
        # Remove it
        response = test_client.post(
            f"/api/v1/photos/{test_photo.id}/toggle-favorite",
            headers=auth_headers,
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["is_favorite"] is False

    def test_toggle_favorite_unauthenticated(
        self,
        test_client: TestClient,
        test_photo: "Photo",
    ):
        """Verify 401 without auth."""
        response = test_client.post(
            f"/api/v1/photos/{test_photo.id}/toggle-favorite",
        )
        
        assert response.status_code == 401

    def test_toggle_favorite_photo_not_found(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 404 for non-existent photo."""
        response = test_client.post(
            "/api/v1/photos/99999/toggle-favorite",
            headers=auth_headers,
        )
        
        assert response.status_code == 404

    def test_bulk_add_favorites_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        test_photo_2: "Photo",
    ):
        """Verify bulk add operation."""
        response = test_client.post(
            "/api/v1/photos/bulk-add-favorites",
            headers=auth_headers,
            json={"photo_ids": [test_photo.id, test_photo_2.id]},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["added_count"] >= 0
        assert data["already_favorite_count"] >= 0

    def test_bulk_remove_favorites_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
        admin_user: "User",
        test_db_session: "Session",
    ):
        """Verify bulk remove operation."""
        from backend.db.models import PhotoFavorite
        
        # Add favorite first
        favorite = PhotoFavorite(photo_id=test_photo.id, username=admin_user.username)
        test_db_session.add(favorite)
        test_db_session.commit()
        
        response = test_client.post(
            "/api/v1/photos/bulk-remove-favorites",
            headers=auth_headers,
            json={"photo_ids": [test_photo.id]},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["removed_count"] >= 0


class TestPhotoRetrieval:
    """Test photo retrieval endpoints."""

    def test_get_photo_by_id_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
    ):
        """Verify photo retrieval by ID."""
        response = test_client.get(
            f"/api/v1/photos/{test_photo.id}",
            headers=auth_headers,
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["id"] == test_photo.id
        assert data["filename"] == test_photo.filename

    def test_get_photo_by_id_not_found(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 404 for non-existent photo."""
        response = test_client.get(
            "/api/v1/photos/99999",
            headers=auth_headers,
        )
        
        assert response.status_code == 404


class TestPhotoDeletion:
    """Test photo deletion endpoints."""

    def test_bulk_delete_photos_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_photo: "Photo",
    ):
        """Verify bulk delete (admin only)."""
        response = test_client.post(
            "/api/v1/photos/bulk-delete",
            headers=auth_headers,
            json={"photo_ids": [test_photo.id]},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "deleted_count" in data
        assert data["deleted_count"] >= 0

    def test_bulk_delete_photos_non_admin(
        self,
        test_client: TestClient,
        regular_auth_headers: dict,
        test_photo: "Photo",
        admin_user,  # Ensure an admin exists to prevent bootstrap
    ):
        """Verify 403 for non-admin users."""
        response = test_client.post(
            "/api/v1/photos/bulk-delete",
            headers=regular_auth_headers,
            json={"photo_ids": [test_photo.id]},
        )
        
        # Should be 403 or 401 depending on implementation
        assert response.status_code in [403, 401]

    def test_bulk_delete_photos_empty_list(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 400 with empty photo_ids."""
        response = test_client.post(
            "/api/v1/photos/bulk-delete",
            headers=auth_headers,
            json={"photo_ids": []},
        )
        
        # May return 200 with 0 deleted or 400
        assert response.status_code in [200, 400]

