"""Tests for database connection and usage logger."""

import asyncio
import pytest
from pathlib import Path
from unittest.mock import AsyncMock, patch, MagicMock

from backend.db.connection import init_db, get_db, close_db
from backend.db.usage import UsageLogger, UsageRecord


class TestDatabaseConnection:
    @pytest.mark.asyncio
    async def test_init_db_creates_file(self, tmp_path):
        db_path = tmp_path / "test.db"
        
        db = await init_db(str(db_path))
        assert db_path.exists()
        await close_db()

    @pytest.mark.asyncio
    async def test_init_db_creates_default_key(self, tmp_path):
        db_path = tmp_path / "test.db"
        
        await init_db(str(db_path))
        db = await get_db()
        
        rows = await db.execute_fetchall("SELECT id FROM api_keys")
        assert len(rows) == 1
        
        # Check key file was created
        key_file = tmp_path / "default_api_key.txt"
        assert key_file.exists()
        
        await close_db()

    @pytest.mark.asyncio
    async def test_get_db_without_init_raises(self):
        # Reset module state
        import backend.db.connection as conn_module
        conn_module._db = None
        
        with pytest.raises(RuntimeError, match="Database not initialized"):
            await get_db()


class TestUsageRecord:
    def test_usage_record_defaults(self):
        record = UsageRecord(
            api_key_id="key1",
            model_id="model1",
            strategy="auto",
            tokens_in=100,
            tokens_out=50,
            cost_usd=0.01,
            latency_ttfb_ms=50.0,
            latency_total_ms=100.0,
        )
        
        assert record.cache_read_tokens == 0
        assert record.cache_creation_tokens == 0
        assert record.was_fallback is False
        assert record.fallback_from is None
        assert record.timestamp > 0

    def test_usage_record_with_cache(self):
        record = UsageRecord(
            api_key_id="key1",
            model_id="model1",
            strategy="auto",
            tokens_in=100,
            tokens_out=50,
            cost_usd=0.01,
            latency_ttfb_ms=50.0,
            latency_total_ms=100.0,
            cache_read_tokens=20,
            cache_creation_tokens=10,
        )
        
        assert record.cache_read_tokens == 20
        assert record.cache_creation_tokens == 10


class TestUsageLogger:
    @pytest.mark.asyncio
    async def test_log_adds_to_buffer(self):
        logger = UsageLogger()
        
        record = UsageRecord(
            api_key_id="key1",
            model_id="model1",
            strategy="auto",
            tokens_in=100,
            tokens_out=50,
            cost_usd=0.01,
            latency_ttfb_ms=50.0,
            latency_total_ms=100.0,
        )
        
        logger.log(record)
        assert len(logger._buffer) == 1

    @pytest.mark.asyncio
    async def test_multiple_logs(self):
        logger = UsageLogger()
        
        for i in range(5):
            record = UsageRecord(
                api_key_id=f"key{i}",
                model_id="model1",
                strategy="auto",
                tokens_in=100,
                tokens_out=50,
                cost_usd=0.01,
                latency_ttfb_ms=50.0,
                latency_total_ms=100.0,
            )
            logger.log(record)
        
        assert len(logger._buffer) == 5

    @pytest.mark.asyncio
    async def test_flush_clears_buffer(self, tmp_path):
        # Initialize DB first
        db_path = tmp_path / "test.db"
        await init_db(str(db_path))
        
        try:
            logger = UsageLogger()
            
            record = UsageRecord(
                api_key_id=None,  # Allow null for testing
                model_id="test/model",
                strategy="auto",
                tokens_in=100,
                tokens_out=50,
                cost_usd=0.01,
                latency_ttfb_ms=50.0,
                latency_total_ms=100.0,
            )
            logger.log(record)
            
            await logger._flush()
            assert len(logger._buffer) == 0
            
            # Verify record was written
            db = await get_db()
            rows = await db.execute_fetchall("SELECT * FROM usage_logs")
            assert len(rows) == 1
        finally:
            await close_db()

    @pytest.mark.asyncio
    async def test_start_stop(self):
        logger = UsageLogger()
        
        await logger.start()
        assert logger._task is not None
        
        await logger.stop()
        assert logger._task.cancelled() or logger._task.done()
