import os
import shutil
import sys
from unittest.mock import MagicMock, Mock, patch

import aiofiles.threadpool
import numpy as np
import pytest


def cleanup_mock_dirs():
    """Clean up any MagicMock directories created during tests"""
    mock_dir = "MagicMock"
    if os.path.exists(mock_dir):
        shutil.rmtree(mock_dir)


@pytest.fixture(autouse=True)
def setup_aiofiles():
    """Setup aiofiles mock wrapper"""
    aiofiles.threadpool.wrap.register(MagicMock)(
        lambda *args, **kwargs: aiofiles.threadpool.AsyncBufferedIOBase(*args, **kwargs)
    )
    yield


@pytest.fixture(autouse=True)
def cleanup():
    """Automatically clean up before and after each test"""
    cleanup_mock_dirs()
    yield
    cleanup_mock_dirs()


# Mock modules before they're imported
sys.modules["transformers"] = Mock()
sys.modules["phonemizer"] = Mock()
sys.modules["models"] = Mock()
sys.modules["models.build_model"] = Mock()
sys.modules["kokoro"] = Mock()
sys.modules["kokoro.generate"] = Mock()
sys.modules["kokoro.phonemize"] = Mock()
sys.modules["kokoro.tokenize"] = Mock()

# Mock ONNX runtime
mock_onnx = Mock()
mock_onnx.InferenceSession = Mock()
mock_onnx.SessionOptions = Mock()
mock_onnx.GraphOptimizationLevel = Mock()
mock_onnx.ExecutionMode = Mock()
sys.modules["onnxruntime"] = mock_onnx

# Create mock settings module
mock_settings_module = Mock()
mock_settings = Mock()
mock_settings.model_dir = "/mock/model/dir"
mock_settings.onnx_model_path = "mock.onnx"
mock_settings_module.settings = mock_settings
sys.modules["api.src.core.config"] = mock_settings_module


class MockTTSModel:
    _instance = None
    _onnx_session = None
    VOICES_DIR = "/mock/voices/dir"

    def __init__(self):
        self._initialized = False

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

    @classmethod
    def initialize(cls, model_dir):
        cls._onnx_session = Mock()
        cls._onnx_session.run = Mock(return_value=[np.zeros(48000)])
        cls._instance._initialized = True
        return cls._onnx_session

    @classmethod
    def setup(cls):
        if not cls._instance._initialized:
            cls.initialize("/mock/model/dir")
        return cls._instance

    @classmethod
    def generate_from_tokens(cls, tokens, voicepack, speed):
        if not cls._instance._initialized:
            raise RuntimeError("Model not initialized. Call setup() first.")
        return np.zeros(48000)

    @classmethod
    def process_text(cls, text, language):
        return "mock phonemes", [1, 2, 3]

    @staticmethod
    def get_device():
        return "cpu"


@pytest.fixture
def mock_tts_service(monkeypatch):
    """Mock TTSService for testing"""
    mock_service = Mock()
    mock_service._get_voice_path.return_value = "/mock/path/voice.pt"
    mock_service._load_voice.return_value = np.zeros((1, 192))

    # Mock TTSModel.generate_from_tokens since we call it directly
    mock_generate = Mock(return_value=np.zeros(48000))
    monkeypatch.setattr(
        "api.src.routers.development.TTSModel.generate_from_tokens", mock_generate
    )

    return mock_service


@pytest.fixture
def mock_audio_service(monkeypatch):
    """Mock AudioService"""
    mock_service = Mock()
    mock_service.convert_audio.return_value = b"mock audio data"
    monkeypatch.setattr("api.src.routers.development.AudioService", mock_service)
    return mock_service