#!/usr/bin/env python3
"""
OSS signed-URL regression tests.

These checks validate provider construction and signed URL generation without
requiring a live OSS service.
"""

from __future__ import annotations

import asyncio
import os
import sys
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, 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.env import OSSConfig
from sandai.operator.storage import OSSStorageProvider, create_storage_provider


def _mock_oss_config() -> OSSConfig:
    return OSSConfig(
        endpoint="oss-cn-beijing.aliyuncs.com",
        vpc_endpoint="oss-cn-beijing-internal.aliyuncs.com",
        access_key_id="test_access_key",
        access_key_secret="test_secret_key",
        bucket_name="test-bucket",
        region="oss-cn-beijing",
        prefix="test-prefix",
    )


def test_provider_initialization_uses_custom_expiry() -> None:
    with patch("sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()), patch(
        "oss2.Bucket"
    ), patch("oss2.Auth"):
        provider = OSSStorageProvider(signed_url_expires=7200)
        assert provider.signed_url_expires == 7200
        assert provider.storage_type == "oss"


def test_provider_initialization_can_read_env_expiry() -> None:
    with patch("sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()), patch(
        "sandai.operator.storage.get_oss_signed_url_expires", return_value=1800
    ) as mock_get_expires, patch("oss2.Bucket"), patch("oss2.Auth"):
        provider = OSSStorageProvider()
        assert provider.signed_url_expires == 1800
        mock_get_expires.assert_called_once()


def test_upload_returns_signed_url_metadata_path() -> None:
    with patch("sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()), patch(
        "oss2.Bucket"
    ) as mock_bucket, patch("oss2.Auth"):
        bucket_instance = MagicMock()
        expected_signed_url = (
            "https://test-bucket.oss-cn-beijing.aliyuncs.com/test-prefix/test-file.txt"
            "?Expires=1234567890&OSSAccessKeyId=test_access_key&Signature=test_signature"
        )
        bucket_instance.sign_url.return_value = expected_signed_url
        mock_bucket.return_value = bucket_instance

        with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as temp_file:
            temp_file.write(b"Test content for OSS upload")
            temp_file_path = temp_file.name

        try:
            provider = OSSStorageProvider(signed_url_expires=3600)
            result = asyncio.run(provider.upload_file(temp_file_path))
            result_url = result[1]["external-url"] if isinstance(result, tuple) else result

            assert result_url == expected_signed_url
            bucket_instance.put_object_from_file.assert_called_once()
            bucket_instance.sign_url.assert_called()
            call_args = bucket_instance.sign_url.call_args
            assert call_args[0][0] == "GET"
            assert call_args[0][2] == 3600
        finally:
            if os.path.exists(temp_file_path):
                os.unlink(temp_file_path)


def test_generate_signed_url_uses_default_expiry() -> None:
    with patch("sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()), patch(
        "oss2.Bucket"
    ) as mock_bucket, patch("oss2.Auth"):
        bucket_instance = MagicMock()
        expected_signed_url = (
            "https://test-bucket.oss-cn-beijing.aliyuncs.com/test-prefix/existing-file.txt"
            "?Expires=1234567890&OSSAccessKeyId=test_access_key&Signature=test_signature"
        )
        bucket_instance.sign_url.return_value = expected_signed_url
        mock_bucket.return_value = bucket_instance

        provider = OSSStorageProvider(signed_url_expires=3600)
        result_url = provider.generate_signed_url("test-prefix/existing-file.txt")

        assert result_url == expected_signed_url
        bucket_instance.sign_url.assert_called_once_with("GET", "test-prefix/existing-file.txt", 3600)


def test_generate_signed_url_can_override_expiry() -> None:
    with patch("sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()), patch(
        "oss2.Bucket"
    ) as mock_bucket, patch("oss2.Auth"):
        bucket_instance = MagicMock()
        expected_signed_url = (
            "https://test-bucket.oss-cn-beijing.aliyuncs.com/test-prefix/existing-file.txt"
            "?Expires=1234567890&OSSAccessKeyId=test_access_key&Signature=test_signature"
        )
        bucket_instance.sign_url.return_value = expected_signed_url
        mock_bucket.return_value = bucket_instance

        provider = OSSStorageProvider(signed_url_expires=3600)
        result_url = provider.generate_signed_url("test-prefix/existing-file.txt", expires=7200)

        assert result_url == expected_signed_url
        bucket_instance.sign_url.assert_called_once_with("GET", "test-prefix/existing-file.txt", 7200)


def test_factory_passes_signed_url_expiry_to_oss_provider() -> None:
    with patch("sandai.operator.storage.get_storage_type_from_env", return_value="oss"), patch(
        "sandai.operator.storage.get_oss_config", return_value=_mock_oss_config()
    ), patch("oss2.Bucket"), patch("oss2.Auth"):
        provider = create_storage_provider(storage_type="oss", signed_url_expires=1800)
        assert isinstance(provider, OSSStorageProvider)
        assert provider.signed_url_expires == 1800


def test_oss_config_validation_marks_complete_and_incomplete_values() -> None:
    complete = OSSConfig(
        endpoint="oss-cn-beijing.aliyuncs.com",
        vpc_endpoint="oss-cn-beijing-internal.aliyuncs.com",
        access_key_id="test_key",
        access_key_secret="test_secret",
        bucket_name="test-bucket",
        region="oss-cn-beijing",
    )
    incomplete = OSSConfig(
        endpoint="",
        vpc_endpoint="",
        access_key_id="test_key",
        access_key_secret="",
        bucket_name="test-bucket",
        region="oss-cn-beijing",
    )

    assert complete.is_configured is True
    assert incomplete.is_configured is False


def test_env_default_signed_url_expiry_is_one_hour() -> None:
    from sandai.operator.env import get_oss_signed_url_expires

    with patch.dict(os.environ, {}, clear=True):
        assert get_oss_signed_url_expires() == 3600


def test_env_custom_signed_url_expiry_is_respected() -> None:
    from sandai.operator.env import get_oss_signed_url_expires

    with patch.dict(os.environ, {"SANDAI_OPERATOR_OSS_SIGNED_URL_EXPIRES": "7200"}, clear=True):
        assert get_oss_signed_url_expires() == 7200


def main() -> int:
    tests = [
        ("custom_expiry", test_provider_initialization_uses_custom_expiry),
        ("env_expiry", test_provider_initialization_can_read_env_expiry),
        ("upload_signed_url", test_upload_returns_signed_url_metadata_path),
        ("default_generate", test_generate_signed_url_uses_default_expiry),
        ("override_generate", test_generate_signed_url_can_override_expiry),
        ("factory_expiry", test_factory_passes_signed_url_expiry_to_oss_provider),
        ("config_validation", test_oss_config_validation_marks_complete_and_incomplete_values),
        ("env_default", test_env_default_signed_url_expiry_is_one_hour),
        ("env_custom", test_env_custom_signed_url_expiry_is_respected),
    ]

    passed = 0
    failed = 0

    print("OSS signed-URL regression 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())
