"""
Tests for the Database abstraction layer.

All tests run against the real SQLite database at vehicle_database/vehicle_database.db.
"""

import pytest

from console.db import Database


@pytest.fixture(scope="module")
def db():
    """Provide a shared Database instance for all tests in this module."""
    return Database()


# =========================================================================
# Vehicle navigation
# =========================================================================

class TestGetBrands:
    def test_returns_nonempty_list(self, db):
        brands = db.get_brands()
        assert isinstance(brands, list)
        assert len(brands) > 0

    def test_each_brand_has_name_key(self, db):
        brands = db.get_brands()
        for b in brands:
            assert "name" in b

    def test_each_brand_has_id_and_country(self, db):
        brands = db.get_brands()
        for b in brands:
            assert "id" in b
            assert "country" in b


class TestGetModels:
    def test_no_filter_returns_nonempty(self, db):
        models = db.get_models()
        assert isinstance(models, list)
        assert len(models) > 0

    def test_filter_by_uppercase_brand(self, db):
        models = db.get_models(brand="TOYOTA")
        assert isinstance(models, list)
        assert len(models) > 0

    def test_filter_by_lowercase_brand(self, db):
        """Brand filtering must be case-insensitive."""
        models = db.get_models(brand="toyota")
        assert isinstance(models, list)
        assert len(models) > 0

    def test_each_model_has_id_and_name(self, db):
        models = db.get_models()
        for m in models[:5]:
            assert "id" in m
            assert "name" in m


class TestGetYears:
    def test_returns_list(self, db):
        years = db.get_years()
        assert isinstance(years, list)
        assert len(years) > 0

    def test_filter_by_brand(self, db):
        years = db.get_years(brand="TOYOTA")
        assert isinstance(years, list)
        assert len(years) > 0

    def test_each_year_has_id_and_year(self, db):
        years = db.get_years()
        for y in years[:5]:
            assert "id" in y
            assert "year" in y


class TestGetEngines:
    def test_returns_list(self, db):
        engines = db.get_engines()
        assert isinstance(engines, list)
        assert len(engines) > 0

    def test_filter_by_brand(self, db):
        engines = db.get_engines(brand="TOYOTA")
        assert isinstance(engines, list)
        assert len(engines) > 0


class TestGetModelYearEngine:
    def test_returns_list(self, db):
        result = db.get_model_year_engine(
            brand="TOYOTA", model="Corolla", year=2020, engine_id=None
        )
        assert isinstance(result, list)


# =========================================================================
# Parts catalog
# =========================================================================

class TestGetCategories:
    def test_returns_exactly_12(self, db):
        categories = db.get_categories()
        assert isinstance(categories, list)
        assert len(categories) == 12

    def test_each_has_expected_keys(self, db):
        categories = db.get_categories()
        for c in categories:
            assert "id" in c
            assert "name" in c


class TestGetGroups:
    def test_returns_nonempty_for_known_category(self, db):
        groups = db.get_groups(category_id=2)
        assert isinstance(groups, list)
        assert len(groups) > 0

    def test_each_group_has_name(self, db):
        groups = db.get_groups(category_id=2)
        for g in groups:
            assert "name" in g


class TestGetParts:
    def test_returns_list(self, db):
        parts = db.get_parts()
        assert isinstance(parts, list)
        assert len(parts) > 0

    def test_pagination(self, db):
        page1 = db.get_parts(page=1, per_page=5)
        page2 = db.get_parts(page=2, per_page=5)
        assert len(page1) <= 5
        assert len(page2) <= 5
        # Pages should contain different items (if enough data)
        if page1 and page2:
            ids1 = {p["id"] for p in page1}
            ids2 = {p["id"] for p in page2}
            assert ids1.isdisjoint(ids2)


class TestGetPart:
    def test_returns_dict_with_oem_part_number(self, db):
        part = db.get_part(1)
        assert isinstance(part, dict)
        assert "oem_part_number" in part

    def test_includes_group_and_category_info(self, db):
        part = db.get_part(1)
        assert "group_name" in part
        assert "category_name" in part

    def test_nonexistent_returns_none(self, db):
        part = db.get_part(999999)
        assert part is None


class TestGetAlternatives:
    def test_returns_list(self, db):
        alts = db.get_alternatives(1)
        assert isinstance(alts, list)


class TestGetCrossReferences:
    def test_returns_list(self, db):
        refs = db.get_cross_references(1)
        assert isinstance(refs, list)


class TestGetVehiclesForPart:
    def test_returns_list(self, db):
        vehicles = db.get_vehicles_for_part(1)
        assert isinstance(vehicles, list)
        assert len(vehicles) > 0


# =========================================================================
# Search
# =========================================================================

class TestSearchParts:
    def test_returns_results_for_brake(self, db):
        results = db.search_parts("brake")
        assert isinstance(results, list)
        assert len(results) > 0

    def test_each_result_has_expected_keys(self, db):
        results = db.search_parts("brake")
        for r in results[:3]:
            assert "id" in r
            assert "name" in r
            assert "oem_part_number" in r


class TestSearchPartNumber:
    def test_returns_results_for_04465(self, db):
        results = db.search_part_number("04465")
        assert isinstance(results, list)
        assert len(results) > 0

    def test_each_result_has_match_type(self, db):
        results = db.search_part_number("04465")
        for r in results:
            assert "match_type" in r


# =========================================================================
# VIN cache
# =========================================================================

class TestVinCache:
    def test_get_nonexistent_vin_returns_none(self, db):
        result = db.get_vin_cache("00000000000000000")
        assert result is None


# =========================================================================
# Stats
# =========================================================================

class TestGetStats:
    def test_returns_dict_with_required_keys(self, db):
        stats = db.get_stats()
        assert isinstance(stats, dict)
        assert "brands" in stats
        assert "models" in stats
        assert "parts" in stats

    def test_counts_are_positive(self, db):
        stats = db.get_stats()
        assert stats["brands"] > 0
        assert stats["models"] > 0
        assert stats["parts"] > 0

    def test_includes_top_brands(self, db):
        stats = db.get_stats()
        assert "top_brands" in stats
        assert isinstance(stats["top_brands"], list)


# =========================================================================
# Manufacturers
# =========================================================================

class TestGetManufacturers:
    def test_returns_nonempty_list(self, db):
        manufacturers = db.get_manufacturers()
        assert isinstance(manufacturers, list)
        assert len(manufacturers) > 0

    def test_each_has_name(self, db):
        manufacturers = db.get_manufacturers()
        for m in manufacturers:
            assert "name" in m
            assert "id" in m


# =========================================================================
# Admin CRUD — smoke tests
# =========================================================================

class TestCrossrefsPaginated:
    def test_returns_list(self, db):
        refs = db.get_crossrefs_paginated(page=1, per_page=5)
        assert isinstance(refs, list)
        assert len(refs) <= 5
