"""Tests for device storage."""

import pytest

from wled_controller.storage.database import Database
from wled_controller.storage.device_store import Device, DeviceStore


@pytest.fixture
def tmp_db(tmp_path):
    """Provide a temporary SQLite Database instance."""
    db = Database(tmp_path / "test.db")
    yield db
    db.close()


@pytest.fixture
def device_store(tmp_db):
    """Provide device store instance."""
    return DeviceStore(tmp_db)


def test_device_creation():
    """Test creating a device."""
    device = Device(
        device_id="test_001",
        name="Test Device",
        url="http://192.168.1.100",
        led_count=150,
    )

    assert device.id == "test_001"
    assert device.name == "Test Device"
    assert device.url == "http://192.168.1.100"
    assert device.led_count == 150
    assert device.enabled is True


def test_device_to_dict():
    """Test converting device to dictionary."""
    device = Device(
        device_id="test_001",
        name="Test Device",
        url="http://192.168.1.100",
        led_count=150,
    )

    data = device.to_dict()

    assert data["id"] == "test_001"
    assert data["name"] == "Test Device"
    assert data["url"] == "http://192.168.1.100"
    assert data["led_count"] == 150


def test_device_from_dict():
    """Test creating device from dictionary."""
    data = {
        "id": "test_001",
        "name": "Test Device",
        "url": "http://192.168.1.100",
        "led_count": 150,
        "enabled": True,
    }

    device = Device.from_dict(data)

    assert device.id == "test_001"
    assert device.name == "Test Device"
    assert device.led_count == 150


def test_device_round_trip():
    """Test converting device to dict and back."""
    original = Device(
        device_id="test_001",
        name="Test Device",
        url="http://192.168.1.100",
        led_count=150,
    )

    data = original.to_dict()
    restored = Device.from_dict(data)

    assert restored.id == original.id
    assert restored.name == original.name
    assert restored.url == original.url
    assert restored.led_count == original.led_count


def test_device_store_init(device_store):
    """Test device store initialization."""
    assert device_store is not None
    assert device_store.count() == 0


def test_create_device(device_store):
    """Test creating a device in store."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    assert device.id is not None
    assert device.name == "Test WLED"
    assert device_store.count() == 1


def test_get_device(device_store):
    """Test retrieving a device."""
    created = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    retrieved = device_store.get_device(created.id)

    assert retrieved is not None
    assert retrieved.id == created.id
    assert retrieved.name == "Test WLED"


def test_get_device_not_found(device_store):
    """Test retrieving non-existent device raises ValueError."""
    with pytest.raises(ValueError, match="not found"):
        device_store.get_device("nonexistent")


def test_get_all_devices(device_store):
    """Test getting all devices."""
    device_store.create_device("Device 1", "http://192.168.1.100", 150)
    device_store.create_device("Device 2", "http://192.168.1.101", 200)

    devices = device_store.get_all_devices()

    assert len(devices) == 2
    assert any(d.name == "Device 1" for d in devices)
    assert any(d.name == "Device 2" for d in devices)


def test_update_device(device_store):
    """Test updating a device."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    updated = device_store.update_device(
        device.id,
        name="Updated WLED",
        enabled=False,
    )

    assert updated.name == "Updated WLED"
    assert updated.enabled is False


def test_update_device_led_count(device_store):
    """Test updating device LED count."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    updated = device_store.update_device(device.id, led_count=200)

    assert updated.led_count == 200


def test_update_device_not_found(device_store):
    """Test updating non-existent device."""
    with pytest.raises(ValueError, match="not found"):
        device_store.update_device("nonexistent", name="New Name")


def test_delete_device(device_store):
    """Test deleting a device."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    device_store.delete_device(device.id)

    assert device_store.count() == 0
    with pytest.raises(ValueError, match="not found"):
        device_store.get_device(device.id)


def test_delete_device_not_found(device_store):
    """Test deleting non-existent device."""
    with pytest.raises(ValueError, match="not found"):
        device_store.delete_device("nonexistent")


def test_device_exists(device_store):
    """Test checking if device exists."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    assert device_store.device_exists(device.id) is True
    assert device_store.device_exists("nonexistent") is False


def test_persistence(tmp_path):
    """Test device persistence across store instances."""
    db = Database(tmp_path / "persist.db")
    # Create store and add device
    store1 = DeviceStore(db)
    device = store1.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )
    device_id = device.id

    # Create new store instance (loads from database)
    store2 = DeviceStore(db)

    # Verify device persisted
    loaded_device = store2.get_device(device_id)
    assert loaded_device is not None
    assert loaded_device.name == "Test WLED"
    assert loaded_device.led_count == 150
    db.close()


def test_clear(device_store):
    """Test clearing all devices."""
    device_store.create_device("Device 1", "http://192.168.1.100", 150)
    device_store.create_device("Device 2", "http://192.168.1.101", 200)

    assert device_store.count() == 2

    device_store.clear()

    assert device_store.count() == 0


def test_update_device_ignores_none_values(device_store):
    """Test that update_device ignores None kwargs."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    updated = device_store.update_device(device.id, name=None, led_count=200)

    assert updated.name == "Test WLED"  # unchanged
    assert updated.led_count == 200


def test_update_device_ignores_unknown_fields(device_store):
    """Test that update_device silently ignores unknown kwargs."""
    device = device_store.create_device(
        name="Test WLED",
        url="http://192.168.1.100",
        led_count=150,
    )

    # Should not raise even with an unknown kwarg
    updated = device_store.update_device(device.id, nonexistent_field="foo")
    assert updated.name == "Test WLED"
