"""Tests for file storage implementation."""

import json
from pathlib import Path
from unittest.mock import patch


from local_deep_research.storage.file import FileReportStorage


class TestFileReportStorageInit:
    """Tests for FileReportStorage initialization."""

    def test_uses_default_directory_when_none(self, tmp_path):
        """Should use default research outputs directory when none provided."""
        with patch(
            "local_deep_research.storage.file.get_research_outputs_directory",
            return_value=tmp_path,
        ):
            storage = FileReportStorage()
            assert storage.base_dir == tmp_path

    def test_uses_provided_directory(self, tmp_path):
        """Should use provided directory."""
        custom_dir = tmp_path / "custom"
        storage = FileReportStorage(base_dir=custom_dir)
        assert storage.base_dir == custom_dir

    def test_creates_directory_if_not_exists(self, tmp_path):
        """Should create directory if it doesn't exist."""
        new_dir = tmp_path / "new_reports"
        storage = FileReportStorage(base_dir=new_dir)
        assert storage.base_dir.exists()


class TestGetReportPath:
    """Tests for _get_report_path method."""

    def test_returns_md_file_path(self, tmp_path):
        """Should return path with .md extension."""
        storage = FileReportStorage(base_dir=tmp_path)
        path = storage._get_report_path("test-uuid")
        assert path == tmp_path / "test-uuid.md"

    def test_returns_path_object(self, tmp_path):
        """Should return Path object."""
        storage = FileReportStorage(base_dir=tmp_path)
        path = storage._get_report_path("test-uuid")
        assert isinstance(path, Path)


class TestGetMetadataPath:
    """Tests for _get_metadata_path method."""

    def test_returns_metadata_json_path(self, tmp_path):
        """Should return path with _metadata.json suffix."""
        storage = FileReportStorage(base_dir=tmp_path)
        path = storage._get_metadata_path("test-uuid")
        assert path == tmp_path / "test-uuid_metadata.json"


class TestSaveReport:
    """Tests for save_report method."""

    def test_saves_report_content(self, tmp_path, sample_report_content):
        """Should save report content to file."""
        storage = FileReportStorage(base_dir=tmp_path)

        # Patch at source location since it's imported inside the method
        with patch(
            "local_deep_research.security.file_write_verifier.write_file_verified"
        ) as mock_write:
            with patch(
                "local_deep_research.security.file_write_verifier.write_json_verified"
            ):
                result = storage.save_report("test-uuid", sample_report_content)

        assert result is True
        mock_write.assert_called_once()

    def test_saves_metadata_when_provided(
        self, tmp_path, sample_report_content, sample_metadata
    ):
        """Should save metadata when provided."""
        storage = FileReportStorage(base_dir=tmp_path)

        with patch(
            "local_deep_research.security.file_write_verifier.write_file_verified"
        ):
            with patch(
                "local_deep_research.security.file_write_verifier.write_json_verified"
            ) as mock_json:
                storage.save_report(
                    "test-uuid", sample_report_content, metadata=sample_metadata
                )

        mock_json.assert_called_once()

    def test_skips_metadata_when_not_provided(
        self, tmp_path, sample_report_content
    ):
        """Should skip metadata save when not provided."""
        storage = FileReportStorage(base_dir=tmp_path)

        with patch(
            "local_deep_research.security.file_write_verifier.write_file_verified"
        ):
            with patch(
                "local_deep_research.security.file_write_verifier.write_json_verified"
            ) as mock_json:
                storage.save_report("test-uuid", sample_report_content)

        mock_json.assert_not_called()

    def test_returns_false_on_error(self, tmp_path, sample_report_content):
        """Should return False on error."""
        storage = FileReportStorage(base_dir=tmp_path)

        with patch(
            "local_deep_research.security.file_write_verifier.write_file_verified",
            side_effect=Exception("write error"),
        ):
            result = storage.save_report("test-uuid", sample_report_content)

        assert result is False


class TestGetReport:
    """Tests for get_report method."""

    def test_returns_content_when_file_exists(
        self, tmp_path, sample_report_content
    ):
        """Should return content when file exists."""
        storage = FileReportStorage(base_dir=tmp_path)
        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        result = storage.get_report("test-uuid")

        assert result == sample_report_content

    def test_returns_none_when_file_not_exists(self, tmp_path):
        """Should return None when file doesn't exist."""
        storage = FileReportStorage(base_dir=tmp_path)

        result = storage.get_report("nonexistent-uuid")

        assert result is None

    def test_returns_none_on_error(self, tmp_path):
        """Should return None on read error."""
        storage = FileReportStorage(base_dir=tmp_path)
        report_path = tmp_path / "test-uuid.md"
        report_path.write_text("content", encoding="utf-8")

        with patch("builtins.open", side_effect=Exception("read error")):
            result = storage.get_report("test-uuid")

        assert result is None


class TestGetReportWithMetadata:
    """Tests for get_report_with_metadata method."""

    def test_returns_content_and_metadata(
        self, tmp_path, sample_report_content, sample_metadata
    ):
        """Should return both content and metadata."""
        storage = FileReportStorage(base_dir=tmp_path)

        # Create files
        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        metadata_path = tmp_path / "test-uuid_metadata.json"
        metadata_path.write_text(json.dumps(sample_metadata), encoding="utf-8")

        result = storage.get_report_with_metadata("test-uuid")

        assert result["content"] == sample_report_content
        assert result["metadata"] == sample_metadata

    def test_returns_empty_metadata_when_missing(
        self, tmp_path, sample_report_content
    ):
        """Should return empty metadata when file missing."""
        storage = FileReportStorage(base_dir=tmp_path)

        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        result = storage.get_report_with_metadata("test-uuid")

        assert result["content"] == sample_report_content
        assert result["metadata"] == {}

    def test_returns_none_when_report_missing(self, tmp_path):
        """Should return None when report doesn't exist."""
        storage = FileReportStorage(base_dir=tmp_path)

        result = storage.get_report_with_metadata("nonexistent")

        assert result is None


class TestDeleteReport:
    """Tests for delete_report method."""

    def test_deletes_report_file(self, tmp_path, sample_report_content):
        """Should delete report file."""
        storage = FileReportStorage(base_dir=tmp_path)

        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        result = storage.delete_report("test-uuid")

        assert result is True
        assert not report_path.exists()

    def test_deletes_metadata_file(
        self, tmp_path, sample_report_content, sample_metadata
    ):
        """Should delete metadata file."""
        storage = FileReportStorage(base_dir=tmp_path)

        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        metadata_path = tmp_path / "test-uuid_metadata.json"
        metadata_path.write_text(json.dumps(sample_metadata), encoding="utf-8")

        storage.delete_report("test-uuid")

        assert not metadata_path.exists()

    def test_returns_false_when_files_not_exist(self, tmp_path):
        """Should return False when no files to delete."""
        storage = FileReportStorage(base_dir=tmp_path)

        result = storage.delete_report("nonexistent")

        assert result is False

    def test_returns_false_on_error(self, tmp_path, sample_report_content):
        """Should return False on delete error."""
        storage = FileReportStorage(base_dir=tmp_path)

        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        with patch.object(
            Path, "unlink", side_effect=Exception("delete error")
        ):
            result = storage.delete_report("test-uuid")

        assert result is False


class TestReportExists:
    """Tests for report_exists method."""

    def test_returns_true_when_file_exists(
        self, tmp_path, sample_report_content
    ):
        """Should return True when file exists."""
        storage = FileReportStorage(base_dir=tmp_path)

        report_path = tmp_path / "test-uuid.md"
        report_path.write_text(sample_report_content, encoding="utf-8")

        result = storage.report_exists("test-uuid")

        assert result is True

    def test_returns_false_when_file_not_exists(self, tmp_path):
        """Should return False when file doesn't exist."""
        storage = FileReportStorage(base_dir=tmp_path)

        result = storage.report_exists("nonexistent")

        assert result is False
