#!/usr/bin/env python3
"""
Test support helpers for running SDK tests without optional third-party deps.
"""

from __future__ import annotations

import importlib.util
import sys
import types


def _module_missing(module_name: str) -> bool:
    try:
        return importlib.util.find_spec(module_name) is None
    except (ModuleNotFoundError, ValueError, AttributeError):
        return module_name not in sys.modules


def install_sdk_dependency_stubs() -> None:
    """Install lightweight stubs for optional SDK dependencies used in tests."""

    if _module_missing("pydantic"):
        pydantic_mod = types.ModuleType("pydantic")

        class BaseModel:
            def __init__(self, **kwargs):
                annotations = {}
                for cls in reversed(self.__class__.__mro__):
                    annotations.update(getattr(cls, "__annotations__", {}))

                for name in annotations:
                    if name in kwargs:
                        value = kwargs[name]
                    elif hasattr(self.__class__, name):
                        default = getattr(self.__class__, name)
                        if callable(default) and not isinstance(default, type):
                            value = default()
                        else:
                            value = default
                    else:
                        raise TypeError(f"Missing required field: {name}")
                    setattr(self, name, value)

                for name, value in kwargs.items():
                    if name not in annotations:
                        setattr(self, name, value)

            def model_dump(self):
                return dict(self.__dict__)

            @classmethod
            def model_json_schema(cls):
                return {
                    "type": "object",
                    "properties": {
                        key: {"type": "string"}
                        for key in getattr(cls, "__annotations__", {})
                    },
                }

            @classmethod
            def model_rebuild(cls):
                return None

        pydantic_mod.BaseModel = BaseModel
        sys.modules["pydantic"] = pydantic_mod

    if _module_missing("dotenv"):
        dotenv = types.ModuleType("dotenv")
        dotenv.load_dotenv = lambda *args, **kwargs: False
        dotenv.find_dotenv = lambda *args, **kwargs: ""
        sys.modules["dotenv"] = dotenv

    if _module_missing("redis"):
        redis_mod = types.ModuleType("redis")

        class DummyRedis:
            def __init__(self, *args, **kwargs):
                pass

            def ping(self):
                return True

            def exists(self, key):
                return 0

        redis_mod.Redis = DummyRedis
        sys.modules["redis"] = redis_mod

    if _module_missing("requests"):
        requests_mod = types.ModuleType("requests")

        class DummyResponse:
            def __init__(self, content: bytes = b""):
                self._content = content

            def raise_for_status(self):
                return None

            def iter_content(self, chunk_size=8192):
                yield self._content

        def get(*args, **kwargs):
            return DummyResponse(b"stubbed-response")

        requests_mod.get = get
        sys.modules["requests"] = requests_mod

    if _module_missing("sentry_sdk"):
        sentry_mod = types.ModuleType("sentry_sdk")
        sentry_mod.__path__ = []
        sentry_mod.init = lambda *args, **kwargs: None
        sentry_mod.capture_exception = lambda *args, **kwargs: None
        sys.modules["sentry_sdk"] = sentry_mod

    if _module_missing("sentry_sdk.integrations"):
        integrations_mod = types.ModuleType("sentry_sdk.integrations")
        integrations_mod.__path__ = []
        sys.modules["sentry_sdk.integrations"] = integrations_mod

    if _module_missing("sentry_sdk.integrations.dedupe"):
        dedupe_mod = types.ModuleType("sentry_sdk.integrations.dedupe")

        class DedupeIntegration:
            pass

        dedupe_mod.DedupeIntegration = DedupeIntegration
        sys.modules["sentry_sdk.integrations.dedupe"] = dedupe_mod

    if _module_missing("celery"):
        celery_mod = types.ModuleType("celery")
        celery_mod.__path__ = []

        class DummyBackend:
            def store_result(self, *args, **kwargs):
                return None

        class DummyCelery:
            def __init__(self, *args, **kwargs):
                self.conf = {}
                self.backend = DummyBackend()
                self.main = args[0] if args else "celery"

            def connection(self):
                raise RuntimeError("Celery stub should not be used in file-channel tests")

        celery_mod.Celery = DummyCelery
        sys.modules["celery"] = celery_mod

    if _module_missing("celery.result"):
        celery_result_mod = types.ModuleType("celery.result")

        class AsyncResult:
            def __init__(self, *args, **kwargs):
                pass

        celery_result_mod.AsyncResult = AsyncResult
        sys.modules["celery.result"] = celery_result_mod

    if _module_missing("kombu"):
        kombu_mod = types.ModuleType("kombu")

        class Queue:
            def __init__(self, name, queue_arguments=None, **kwargs):
                self.name = name
                self.queue_arguments = queue_arguments or {}

        kombu_mod.Queue = Queue
        sys.modules["kombu"] = kombu_mod

    if _module_missing("oss2"):
        oss2_mod = types.ModuleType("oss2")

        class Auth:
            def __init__(self, *args, **kwargs):
                pass

        class Bucket:
            def __init__(self, *args, **kwargs):
                pass

            def put_object_from_file(self, *args, **kwargs):
                return None

            def sign_url(self, *args, **kwargs):
                return "http://stubbed-oss-url"

            def get_object_to_file(self, *args, **kwargs):
                return None

        class NoSuchKey(Exception):
            pass

        class NoSuchBucket(Exception):
            pass

        class OssError(Exception):
            pass

        oss2_mod.Auth = Auth
        oss2_mod.Bucket = Bucket
        oss2_mod.exceptions = types.SimpleNamespace(
            NoSuchKey=NoSuchKey,
            NoSuchBucket=NoSuchBucket,
            OssError=OssError,
        )
        sys.modules["oss2"] = oss2_mod

    if _module_missing("boto3"):
        boto3_mod = types.ModuleType("boto3")

        class DummyS3Client:
            def head_bucket(self, *args, **kwargs):
                return None

            def create_bucket(self, *args, **kwargs):
                return None

            def upload_file(self, *args, **kwargs):
                return None

            def download_file(self, *args, **kwargs):
                return None

        boto3_mod.client = lambda *args, **kwargs: DummyS3Client()
        sys.modules["boto3"] = boto3_mod

    if _module_missing("botocore"):
        sys.modules["botocore"] = types.ModuleType("botocore")

    if _module_missing("botocore.exceptions"):
        botocore_ex_mod = types.ModuleType("botocore.exceptions")

        class ClientError(Exception):
            def __init__(self, *args, **kwargs):
                super().__init__(*args)
                self.response = {"Error": {"Code": "Unknown"}}

        botocore_ex_mod.ClientError = ClientError
        sys.modules["botocore.exceptions"] = botocore_ex_mod
