"""Tests for storage abstraction layer."""

import pytest

from screenshot_batch.storage import LocalFileStorage, NullStorage


class TestNullStorage:
    """Tests for NullStorage implementation."""

    def test_download_file_returns_false(self, tmp_path):
        """NullStorage download_file always returns False."""
        storage = NullStorage()
        dest = tmp_path / "file.txt"
        assert storage.download_file("blob/file.txt", dest) is False
        assert not dest.exists()

    def test_download_prefix_returns_false(self, tmp_path):
        """NullStorage download_prefix always returns False."""
        storage = NullStorage()
        dest_dir = tmp_path / "downloads"
        assert storage.download_prefix("blob/", dest_dir) is False
        assert not dest_dir.exists()

    def test_upload_file_raises_error(self, tmp_path):
        """NullStorage upload_file raises RuntimeError."""
        storage = NullStorage()
        src = tmp_path / "file.txt"
        src.write_text("content")

        with pytest.raises(RuntimeError, match="NullStorage does not support uploads"):
            storage.upload_file(src, "blob/file.txt")

    def test_list_blobs_yields_nothing(self):
        """NullStorage list_blobs yields no items."""
        storage = NullStorage()
        blobs = list(storage.list_blobs("prefix/"))
        assert blobs == []


class TestLocalFileStorage:
    """Tests for LocalFileStorage implementation."""

    def test_initialization_creates_base_dir(self, tmp_path):
        """LocalFileStorage creates base directory on init."""
        base_dir = tmp_path / "storage"
        assert not base_dir.exists()

        storage = LocalFileStorage(base_dir)

        assert base_dir.exists()
        assert base_dir.is_dir()
        assert storage.base_dir == base_dir

    def test_download_file_success(self, tmp_path):
        """LocalFileStorage successfully downloads existing file."""
        base_dir = tmp_path / "storage"
        storage = LocalFileStorage(base_dir)

        # Create source file
        src_path = base_dir / "blob" / "file.txt"
        src_path.parent.mkdir(parents=True)
        src_path.write_text("test content")

        # Download to destination
        dest = tmp_path / "dest" / "file.txt"
        result = storage.download_file("blob/file.txt", dest)

        assert result is True
        assert dest.exists()
        assert dest.read_text() == "test content"

    def test_download_file_missing_source(self, tmp_path):
        """LocalFileStorage download_file returns False for missing source."""
        storage = LocalFileStorage(tmp_path / "storage")
        dest = tmp_path / "dest" / "file.txt"

        result = storage.download_file("nonexistent/file.txt", dest)

        assert result is False
        assert not dest.exists()

    def test_download_prefix_success(self, tmp_path):
        """LocalFileStorage downloads all files with prefix."""
        base_dir = tmp_path / "storage"
        storage = LocalFileStorage(base_dir)

        # Create multiple files with prefix
        files = ["batch/job1/file1.txt", "batch/job1/file2.txt", "batch/job1/sub/file3.txt"]
        for file_path in files:
            full_path = base_dir / file_path
            full_path.parent.mkdir(parents=True, exist_ok=True)
            full_path.write_text(f"content of {file_path}")

        # Download prefix
        dest_dir = tmp_path / "downloads"
        result = storage.download_prefix("batch/job1", dest_dir)

        assert result is True
        assert (dest_dir / "file1.txt").exists()
        assert (dest_dir / "file2.txt").exists()
        assert (dest_dir / "sub" / "file3.txt").exists()

    def test_download_prefix_missing_source(self, tmp_path):
        """LocalFileStorage download_prefix returns False for missing source."""
        storage = LocalFileStorage(tmp_path / "storage")
        dest_dir = tmp_path / "downloads"

        result = storage.download_prefix("nonexistent/", dest_dir)

        assert result is False

    def test_upload_file_success(self, tmp_path):
        """LocalFileStorage successfully uploads file."""
        base_dir = tmp_path / "storage"
        storage = LocalFileStorage(base_dir)

        # Create source file
        src = tmp_path / "source" / "file.txt"
        src.parent.mkdir(parents=True)
        src.write_text("upload content")

        # Upload
        url = storage.upload_file(src, "blob/uploaded.txt")

        # Verify
        assert url.startswith("file://")
        dest_path = base_dir / "blob" / "uploaded.txt"
        assert dest_path.exists()
        assert dest_path.read_text() == "upload content"

    def test_upload_file_creates_parent_dirs(self, tmp_path):
        """LocalFileStorage creates parent directories when uploading."""
        base_dir = tmp_path / "storage"
        storage = LocalFileStorage(base_dir)

        src = tmp_path / "file.txt"
        src.write_text("content")

        storage.upload_file(src, "deep/nested/path/file.txt")

        dest = base_dir / "deep" / "nested" / "path" / "file.txt"
        assert dest.exists()

    def test_list_blobs_returns_all_files(self, tmp_path):
        """LocalFileStorage lists all files with prefix."""
        base_dir = tmp_path / "storage"
        storage = LocalFileStorage(base_dir)

        # Create multiple files
        files = [
            "batch/job1/file1.txt",
            "batch/job1/file2.txt",
            "batch/job2/file3.txt",
            "other/file4.txt",
        ]
        for file_path in files:
            full_path = base_dir / file_path
            full_path.parent.mkdir(parents=True, exist_ok=True)
            full_path.write_text("content")

        # List blobs with prefix
        blobs = list(storage.list_blobs("batch/job1"))

        assert len(blobs) == 2
        assert any("file1.txt" in blob for blob in blobs)
        assert any("file2.txt" in blob for blob in blobs)

    def test_list_blobs_empty_prefix(self, tmp_path):
        """LocalFileStorage returns empty list for missing prefix."""
        storage = LocalFileStorage(tmp_path / "storage")
        blobs = list(storage.list_blobs("nonexistent/"))
        assert blobs == []
