"""Tests for database utilities."""

import os
import tempfile
import pytest
from pathlib import Path
from unittest.mock import patch

# Need to patch DB_PATH before importing database module
@pytest.fixture(autouse=True)
def temp_db():
    """Use a temporary database for each test."""
    with tempfile.TemporaryDirectory() as tmpdir:
        test_db_path = Path(tmpdir) / 'test_intercept.db'
        test_db_dir = Path(tmpdir)

        with patch('utils.database.DB_PATH', test_db_path), \
             patch('utils.database.DB_DIR', test_db_dir):
            # Import after patching
            from utils.database import init_db, close_db

            init_db()
            yield test_db_path
            close_db()


class TestSettingsCRUD:
    """Tests for settings CRUD operations."""

    def test_set_and_get_string(self, temp_db):
        """Test setting and getting string values."""
        from utils.database import set_setting, get_setting

        set_setting('test_key', 'test_value')
        assert get_setting('test_key') == 'test_value'

    def test_set_and_get_int(self, temp_db):
        """Test setting and getting integer values."""
        from utils.database import set_setting, get_setting

        set_setting('int_key', 42)
        result = get_setting('int_key')
        assert result == 42
        assert isinstance(result, int)

    def test_set_and_get_float(self, temp_db):
        """Test setting and getting float values."""
        from utils.database import set_setting, get_setting

        set_setting('float_key', 3.14)
        result = get_setting('float_key')
        assert result == 3.14
        assert isinstance(result, float)

    def test_set_and_get_bool(self, temp_db):
        """Test setting and getting boolean values."""
        from utils.database import set_setting, get_setting

        set_setting('bool_true', True)
        set_setting('bool_false', False)

        assert get_setting('bool_true') is True
        assert get_setting('bool_false') is False

    def test_set_and_get_dict(self, temp_db):
        """Test setting and getting dictionary values."""
        from utils.database import set_setting, get_setting

        test_dict = {'name': 'test', 'value': 123, 'nested': {'a': 1}}
        set_setting('dict_key', test_dict)
        result = get_setting('dict_key')

        assert result == test_dict
        assert result['nested']['a'] == 1

    def test_set_and_get_list(self, temp_db):
        """Test setting and getting list values."""
        from utils.database import set_setting, get_setting

        test_list = [1, 2, 3, 'four', {'five': 5}]
        set_setting('list_key', test_list)
        result = get_setting('list_key')

        assert result == test_list

    def test_get_nonexistent_key(self, temp_db):
        """Test getting a key that doesn't exist."""
        from utils.database import get_setting

        assert get_setting('nonexistent') is None
        assert get_setting('nonexistent', 'default') == 'default'

    def test_update_existing_setting(self, temp_db):
        """Test updating an existing setting."""
        from utils.database import set_setting, get_setting

        set_setting('update_key', 'original')
        assert get_setting('update_key') == 'original'

        set_setting('update_key', 'updated')
        assert get_setting('update_key') == 'updated'

    def test_delete_setting(self, temp_db):
        """Test deleting a setting."""
        from utils.database import set_setting, get_setting, delete_setting

        set_setting('delete_key', 'value')
        assert get_setting('delete_key') == 'value'

        result = delete_setting('delete_key')
        assert result is True
        assert get_setting('delete_key') is None

    def test_delete_nonexistent_setting(self, temp_db):
        """Test deleting a setting that doesn't exist."""
        from utils.database import delete_setting

        result = delete_setting('nonexistent_key')
        assert result is False

    def test_get_all_settings(self, temp_db):
        """Test getting all settings."""
        from utils.database import set_setting, get_all_settings

        set_setting('key1', 'value1')
        set_setting('key2', 42)
        set_setting('key3', True)

        all_settings = get_all_settings()

        assert 'key1' in all_settings
        assert all_settings['key1'] == 'value1'
        assert all_settings['key2'] == 42
        assert all_settings['key3'] is True


class TestSignalHistory:
    """Tests for signal history operations."""

    def test_add_and_get_signal_reading(self, temp_db):
        """Test adding and retrieving signal readings."""
        from utils.database import add_signal_reading, get_signal_history

        add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -65)
        add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -62)
        add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -70)

        history = get_signal_history('wifi', 'AA:BB:CC:DD:EE:FF')

        assert len(history) == 3
        # Results should be in chronological order
        assert history[0]['signal'] == -65
        assert history[1]['signal'] == -62
        assert history[2]['signal'] == -70

    def test_signal_history_with_metadata(self, temp_db):
        """Test signal readings with metadata."""
        from utils.database import add_signal_reading, get_signal_history

        metadata = {'channel': 6, 'ssid': 'TestNetwork'}
        add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -65, metadata)

        history = get_signal_history('wifi', 'AA:BB:CC:DD:EE:FF')

        assert len(history) == 1
        assert history[0]['metadata'] == metadata

    def test_signal_history_limit(self, temp_db):
        """Test signal history respects limit parameter."""
        from utils.database import add_signal_reading, get_signal_history

        for i in range(10):
            add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -60 - i)

        history = get_signal_history('wifi', 'AA:BB:CC:DD:EE:FF', limit=5)
        assert len(history) == 5

    def test_signal_history_different_devices(self, temp_db):
        """Test signal history isolates different devices."""
        from utils.database import add_signal_reading, get_signal_history

        add_signal_reading('wifi', 'AA:AA:AA:AA:AA:AA', -65)
        add_signal_reading('wifi', 'BB:BB:BB:BB:BB:BB', -70)

        history_a = get_signal_history('wifi', 'AA:AA:AA:AA:AA:AA')
        history_b = get_signal_history('wifi', 'BB:BB:BB:BB:BB:BB')

        assert len(history_a) == 1
        assert len(history_b) == 1
        assert history_a[0]['signal'] == -65
        assert history_b[0]['signal'] == -70

    def test_cleanup_old_signal_history(self, temp_db):
        """Test cleanup of old signal history."""
        from utils.database import add_signal_reading, cleanup_old_signal_history

        add_signal_reading('wifi', 'AA:BB:CC:DD:EE:FF', -65)

        # Cleanup with 0 hours should remove everything
        deleted = cleanup_old_signal_history(max_age_hours=0)
        # Note: This may or may not delete depending on timing
        assert isinstance(deleted, int)


class TestDeviceCorrelations:
    """Tests for device correlation operations."""

    def test_add_and_get_correlation(self, temp_db):
        """Test adding and retrieving correlations."""
        from utils.database import add_correlation, get_correlations

        add_correlation(
            wifi_mac='AA:AA:AA:AA:AA:AA',
            bt_mac='BB:BB:BB:BB:BB:BB',
            confidence=0.85,
            metadata={'reason': 'timing'}
        )

        correlations = get_correlations(min_confidence=0.5)

        assert len(correlations) >= 1
        found = next(
            (c for c in correlations
             if c['wifi_mac'] == 'AA:AA:AA:AA:AA:AA'),
            None
        )
        assert found is not None
        assert found['bt_mac'] == 'BB:BB:BB:BB:BB:BB'
        assert found['confidence'] == 0.85

    def test_correlation_confidence_filter(self, temp_db):
        """Test correlation filtering by confidence."""
        from utils.database import add_correlation, get_correlations

        add_correlation('AA:AA:AA:AA:AA:AA', 'BB:BB:BB:BB:BB:BB', 0.9)
        add_correlation('CC:CC:CC:CC:CC:CC', 'DD:DD:DD:DD:DD:DD', 0.4)

        high_confidence = get_correlations(min_confidence=0.7)
        all_confidence = get_correlations(min_confidence=0.3)

        assert len(high_confidence) == 1
        assert len(all_confidence) == 2

    def test_correlation_upsert(self, temp_db):
        """Test that correlations are updated on conflict."""
        from utils.database import add_correlation, get_correlations

        add_correlation('AA:AA:AA:AA:AA:AA', 'BB:BB:BB:BB:BB:BB', 0.5)
        add_correlation('AA:AA:AA:AA:AA:AA', 'BB:BB:BB:BB:BB:BB', 0.9)

        correlations = get_correlations(min_confidence=0.0)

        matching = [c for c in correlations
                   if c['wifi_mac'] == 'AA:AA:AA:AA:AA:AA']
        assert len(matching) == 1
        assert matching[0]['confidence'] == 0.9
