import numpy as np
import pytest

from supervision.detection.core import Detections


@pytest.fixture
def detections_50_50():
    return Detections(
        xyxy=np.array([[10, 10, 50, 50]], dtype=np.float32),
        confidence=np.array([0.9]),
        class_id=np.array([0]),
    )


@pytest.fixture
def targets_50_50():
    return Detections(
        xyxy=np.array([[10, 10, 50, 50]], dtype=np.float32),
        class_id=np.array([0]),
    )


@pytest.fixture
def dummy_prediction():
    return Detections(
        xyxy=np.array([[10, 10, 20, 20]], dtype=np.float32),
        confidence=np.array([0.8]),
        class_id=np.array([0]),
    )


@pytest.fixture
def predictions_no_overlap():
    return Detections(
        xyxy=np.array([[10, 10, 20, 20]], dtype=np.float32),
        confidence=np.array([0.9]),
        class_id=np.array([0]),
    )


@pytest.fixture
def targets_no_overlap():
    return Detections(
        xyxy=np.array([[100, 100, 110, 110]], dtype=np.float32),
        class_id=np.array([0]),
    )


@pytest.fixture
def targets_two_objects_class_0():
    return Detections(
        xyxy=np.array(
            [
                [10, 10, 50, 50],
                [100, 100, 110, 110],
            ],
            dtype=np.float32,
        ),
        class_id=np.array([0, 0]),
    )


@pytest.fixture
def predictions_multiple_classes():
    return Detections(
        xyxy=np.array(
            [
                [10, 10, 50, 50],  # class 0, matches target
                [60, 60, 100, 100],  # class 1, matches target
                [120, 120, 130, 130],  # class 1, false positive
            ],
            dtype=np.float32,
        ),
        confidence=np.array([0.9, 0.8, 0.7]),
        class_id=np.array([0, 1, 1]),
    )


@pytest.fixture
def targets_multiple_classes():
    return Detections(
        xyxy=np.array(
            [
                [10, 10, 50, 50],  # class 0
                [60, 60, 100, 100],  # class 1
            ],
            dtype=np.float32,
        ),
        class_id=np.array([0, 1]),
    )


@pytest.fixture
def predictions_iou_064():
    return Detections(
        xyxy=np.array([[15, 15, 55, 55]], dtype=np.float32),
        confidence=np.array([0.9]),
        class_id=np.array([0]),
    )


@pytest.fixture
def targets_iou_064():
    return Detections(
        xyxy=np.array([[10, 10, 60, 60]], dtype=np.float32),
        class_id=np.array([0]),
    )


@pytest.fixture
def predictions_confidence_ranking():
    return Detections(
        xyxy=np.array(
            [
                [10, 10, 50, 50],
                [11, 11, 49, 49],
            ],
            dtype=np.float32,
        ),
        confidence=np.array([0.6, 0.9]),
        class_id=np.array([0, 0]),
    )


@pytest.fixture
def prediction_class_1():
    return Detections(
        xyxy=np.array([[60, 60, 100, 100]], dtype=np.float32),
        confidence=np.array([0.8]),
        class_id=np.array([1]),
    )


@pytest.fixture
def target_class_1():
    return Detections(
        xyxy=np.array([[60, 60, 100, 100]], dtype=np.float32),
        class_id=np.array([1]),
    )


def _yolo_dataset_factory(
    tmp_path,
    num_images: int = 20,
    classes: list[str] | None = None,
    objects_per_image_range: tuple[int, int] = (1, 3),
):
    """
    Factory function to create synthetic YOLO-format datasets with custom parameters.

    Args:
        tmp_path: Pytest tmp_path fixture
        num_images: Number of images to generate
        classes: List of class names
        objects_per_image_range: Range of objects per image as (min, max)

    Returns:
        dict with dataset paths and metadata
    """
    from tests.helpers import create_yolo_dataset

    if classes is None:
        classes = ["dog", "cat", "person"]

    return create_yolo_dataset(
        dataset_dir=str(tmp_path / "yolo_dataset"),
        num_images=num_images,
        image_size=(640, 640, 3),
        classes=classes,
        objects_per_image_range=objects_per_image_range,
        seed=42,
    )


@pytest.fixture
def yolo_dataset_structure(tmp_path):
    """
    Synthetic YOLO-format dataset for testing confusion matrix and detection metrics.

    Configuration:
    - 20 images
    - 640x640 resolution
    - 3 classes: ["dog", "cat", "person"]
    - 1-3 objects per image

    Use this for tests that need multi-class scenarios (3+ classes).

    Returns:
        dict with dataset paths and metadata
    """
    return _yolo_dataset_factory(
        tmp_path,
        num_images=20,
        classes=["dog", "cat", "person"],
        objects_per_image_range=(1, 3),
    )


@pytest.fixture
def yolo_dataset_two_classes(tmp_path):
    """
    Synthetic YOLO-format dataset for testing mAR and binary classification metrics.

    Configuration:
    - 15 images
    - 640x640 resolution
    - 2 classes: ["class_0", "class_1"]
    - 2-4 objects per image

    Use this for tests that specifically need 2-class scenarios or depend on
    specific class distributions (e.g., mAR @ K per-image limiting tests).

    Returns:
        dict with dataset paths and metadata
    """
    return _yolo_dataset_factory(
        tmp_path,
        num_images=15,
        classes=["class_0", "class_1"],
        objects_per_image_range=(2, 4),
    )
