import pytest
import sys
from unittest.mock import patch, MagicMock

# Mock out all third-party libraries so the tests run instantly without gigabytes of downloads
sys.modules['numpy'] = MagicMock()
sys.modules['cv2'] = MagicMock()
sys.modules['sklearn'] = MagicMock()
sys.modules['sklearn.ensemble'] = MagicMock()
sys.modules['torch'] = MagicMock()
sys.modules['nltk'] = MagicMock()
sys.modules['nltk.tokenize'] = MagicMock()
sys.modules['ultralytics'] = MagicMock()

from aiforge.core.registry import get_operator
from aiforge.core.plugin_loader import load_plugin

# We load plugins gracefully
load_plugin("vision")
load_plugin("ml")
load_plugin("dl")
load_plugin("nlp")
load_plugin("yolo")

def test_ml_plugin_rf():
    op_train = get_operator("train_rf")
    op_predict = get_operator("predict_rf")
    
    mock_model = MagicMock()
    sys.modules['sklearn.ensemble'].RandomForestClassifier.return_value = mock_model
    mock_model.predict.return_value = [0, 1, 1, 0]
    
    X, y = [0, 1], [1, 0]
    
    model = op_train.run((X, y), n_estimators=10)
    assert model is not None
    
    preds = op_predict.run(X, model=model)
    assert len(preds) == 4

def test_nlp_plugin():
    op_tokenize = get_operator("tokenize")
    op_lower = get_operator("lowercase")
    
    sys.modules['nltk.tokenize'].word_tokenize.return_value = ["hello", "world", "!"]
    
    data = "Hello World!"
    lower_data = op_lower.run(data)
    assert lower_data == "hello world!"
    
    tokens = op_tokenize.run(lower_data)
    assert "hello" in tokens

def test_vision_plugin_mocked():
    op_blur = get_operator("blur")
    op_blur.run([1, 2, 3], kernel=5)
    sys.modules['cv2'].GaussianBlur.assert_called_once()

def test_dl_plugin_mocked():
    op_tensor = get_operator("tensor_conversion")
    sys.modules['numpy'].ndarray = type("DummyNdarray", (), {})
    op_tensor.run([1, 2, 3])
    sys.modules['torch'].tensor.assert_called_once()

def test_yolo_plugin_mocked():
    mock_yolo_instance = MagicMock()
    sys.modules['ultralytics'].YOLO.return_value = mock_yolo_instance
    
    op_yolo = get_operator("detect_yolo")
    op_yolo.run("fake_image.jpg", model_name="yolov8n.pt")
    
    sys.modules['ultralytics'].YOLO.assert_called_once_with("yolov8n.pt")
    mock_yolo_instance.assert_called_once_with("fake_image.jpg")

def test_ml_svm_kmeans_pca():
    op_train_svm = get_operator("train_svm")
    op_train_kmeans = get_operator("train_kmeans")
    op_train_pca = get_operator("train_pca")
    assert op_train_svm is not None
    assert op_train_kmeans is not None
    assert op_train_pca is not None

def test_dl_mlp():
    op_build_mlp = get_operator("build_mlp")
    assert op_build_mlp is not None

def test_nlp_stopwords_summary():
    op_remove_stopwords = get_operator("remove_stopwords")
    op_summarize_text = get_operator("summarize_text")
    assert op_remove_stopwords is not None
    assert op_summarize_text is not None

def test_vision_new_ops():
    op_resize = get_operator("resize_image")
    op_threshold = get_operator("threshold_image")
    op_rotate = get_operator("rotate_image")
    assert op_resize is not None
    assert op_threshold is not None
    assert op_rotate is not None

def test_yolo_draw():
    op_draw = get_operator("yolo_draw_boxes")
    assert op_draw is not None
