#!/usr/bin/env python3
"""
Processor/storage integration regression tests.
"""

from __future__ import annotations

import asyncio
import os
import sys
import tempfile
from pathlib import Path
from unittest.mock import Mock, patch

from test_support import install_sdk_dependency_stubs

install_sdk_dependency_stubs()

sys.path.insert(0, str(Path(__file__).parent.parent))

from sandai.operator.processor import BatchProcessor


def test_processor_storage_integration_uses_fake_by_default() -> bool:
    with patch.dict(os.environ, {"SANDAI_OPERATOR_STORAGE_TYPE": "fake"}):
        processor = BatchProcessor("test-operator", "v1", ignore_nongil_check=True)
        processor._setup_temp_directory()
        provider = processor._get_storage_provider()
        assert provider.storage_type == "fake"

        with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
            f.write("processor storage integration")
            test_file_path = f.name

        try:
            uri, meta = asyncio.run(processor._upload_to_storage(test_file_path))
            assert uri.startswith("fake://")
            assert meta["type"] == "fake"
            return True
        finally:
            if os.path.exists(test_file_path):
                os.unlink(test_file_path)


def test_processor_convert_output_uploads_and_cleans_local_file() -> bool:
    with patch.dict(os.environ, {"SANDAI_OPERATOR_STORAGE_TYPE": "fake"}):
        processor = BatchProcessor("test-operator", "v1", ignore_nongil_check=True)
        processor._setup_temp_directory()

        with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
            f.write("cleanup me")
            test_file_path = f.name

        try:
            uri, meta = asyncio.run(processor._upload_to_storage(test_file_path))
            assert uri.startswith("fake://")
            assert meta["type"] == "fake"
            asyncio.run(asyncio.get_event_loop().run_in_executor(None, processor._cleanup_local_file, test_file_path))
            assert not os.path.exists(test_file_path)
            return True
        except RuntimeError:
            loop = asyncio.new_event_loop()
            try:
                loop.run_until_complete(loop.run_in_executor(None, processor._cleanup_local_file, test_file_path))
            finally:
                loop.close()
            assert not os.path.exists(test_file_path)
            return True


def test_processor_storage_failure_propagates() -> bool:
    with patch.dict(os.environ, {"SANDAI_OPERATOR_STORAGE_TYPE": "fake"}):
        processor = BatchProcessor("test-operator", "v1", ignore_nongil_check=True)
        processor._setup_temp_directory()

        with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
            f.write("storage failure")
            test_file_path = f.name

        try:
            processor._storage_provider = Mock()
            processor._storage_provider.upload_file.side_effect = Exception("mock storage failure")
            try:
                asyncio.run(processor._upload_to_storage(test_file_path))
                raise AssertionError("expected upload failure")
            except Exception as exc:
                assert "mock storage failure" in str(exc)
            return True
        finally:
            if os.path.exists(test_file_path):
                os.unlink(test_file_path)


def test_processor_storage_type_switching_is_explicit_and_mocked() -> bool:
    with patch.dict(os.environ, {"SANDAI_OPERATOR_STORAGE_TYPE": "fake"}):
        fake_processor = BatchProcessor("test-operator", "v1", ignore_nongil_check=True)
        assert fake_processor._get_storage_provider().storage_type == "fake"

    with patch.dict(os.environ, {"SANDAI_OPERATOR_STORAGE_TYPE": "minio"}):
        with patch("boto3.client") as mock_boto3:
            mock_s3_client = Mock()
            mock_s3_client.head_bucket.return_value = {}
            mock_boto3.return_value = mock_s3_client
            minio_processor = BatchProcessor("test-operator", "v1", ignore_nongil_check=True)
            assert minio_processor._get_storage_provider().storage_type == "minio"

    return True


def main() -> int:
    tests = [
        ("default_fake", test_processor_storage_integration_uses_fake_by_default),
        ("upload_and_cleanup", test_processor_convert_output_uploads_and_cleans_local_file),
        ("failure_propagation", test_processor_storage_failure_propagates),
        ("type_switching", test_processor_storage_type_switching_is_explicit_and_mocked),
    ]

    passed = 0
    failed = 0

    print("Processor storage integration tests")
    print("=" * 60)
    for name, test_func in tests:
        try:
            test_func()
            print(f"PASS {name}")
            passed += 1
        except Exception as exc:
            print(f"FAIL {name}: {exc}")
            import traceback
            traceback.print_exc()
            failed += 1
    print("=" * 60)
    print(f"passed={passed} failed={failed}")
    return 0 if failed == 0 else 1


if __name__ == "__main__":
    raise SystemExit(main())
