from sqlite_utils.db import Index
import pytest


def test_lookup_new_table(fresh_db):
    species = fresh_db["species"]
    palm_id = species.lookup({"name": "Palm"})
    oak_id = species.lookup({"name": "Oak"})
    cherry_id = species.lookup({"name": "Cherry"})
    assert palm_id == species.lookup({"name": "Palm"})
    assert oak_id == species.lookup({"name": "Oak"})
    assert cherry_id == species.lookup({"name": "Cherry"})
    assert palm_id != oak_id != cherry_id
    # Ensure the correct indexes were created
    assert [
        Index(
            seq=0,
            name="idx_species_name",
            unique=1,
            origin="c",
            partial=0,
            columns=["name"],
        )
    ] == species.indexes


def test_lookup_new_table_compound_key(fresh_db):
    species = fresh_db["species"]
    palm_id = species.lookup({"name": "Palm", "type": "Tree"})
    oak_id = species.lookup({"name": "Oak", "type": "Tree"})
    assert palm_id == species.lookup({"name": "Palm", "type": "Tree"})
    assert oak_id == species.lookup({"name": "Oak", "type": "Tree"})
    assert [
        Index(
            seq=0,
            name="idx_species_name_type",
            unique=1,
            origin="c",
            partial=0,
            columns=["name", "type"],
        )
    ] == species.indexes


def test_lookup_adds_unique_constraint_to_existing_table(fresh_db):
    species = fresh_db.table("species", pk="id")
    palm_id = species.insert({"name": "Palm"}).last_pk
    species.insert({"name": "Oak"})
    assert [] == species.indexes
    assert palm_id == species.lookup({"name": "Palm"})
    assert [
        Index(
            seq=0,
            name="idx_species_name",
            unique=1,
            origin="c",
            partial=0,
            columns=["name"],
        )
    ] == species.indexes


def test_lookup_fails_if_constraint_cannot_be_added(fresh_db):
    species = fresh_db.table("species", pk="id")
    species.insert_all([{"id": 1, "name": "Palm"}, {"id": 2, "name": "Palm"}])
    # This will fail because the name column is not unique
    with pytest.raises(Exception, match="UNIQUE constraint failed"):
        species.lookup({"name": "Palm"})


def test_lookup_with_extra_values(fresh_db):
    species = fresh_db["species"]
    id = species.lookup({"name": "Palm", "type": "Tree"}, {"first_seen": "2020-01-01"})
    assert species.get(id) == {
        "id": 1,
        "name": "Palm",
        "type": "Tree",
        "first_seen": "2020-01-01",
    }
    # A subsequent lookup() should ignore the second dictionary
    id2 = species.lookup({"name": "Palm", "type": "Tree"}, {"first_seen": "2021-02-02"})
    assert id2 == id
    assert species.get(id2) == {
        "id": 1,
        "name": "Palm",
        "type": "Tree",
        "first_seen": "2020-01-01",
    }


def test_lookup_with_extra_insert_parameters(fresh_db):
    other_table = fresh_db["other_table"]
    other_table.insert({"id": 1, "name": "Name"}, pk="id")
    species = fresh_db["species"]
    id = species.lookup(
        {"name": "Palm", "type": "Tree"},
        {
            "first_seen": "2020-01-01",
            "make_not_null": 1,
            "fk_to_other": 1,
            "default_is_dog": "cat",
            "extract_this": "This is extracted",
            "convert_to_upper": "upper",
            "make_this_integer": "2",
            "this_at_front": 1,
        },
        pk="renamed_id",
        foreign_keys=(("fk_to_other", "other_table", "id"),),
        column_order=("this_at_front",),
        not_null={"make_not_null"},
        defaults={"default_is_dog": "dog"},
        extracts=["extract_this"],
        conversions={"convert_to_upper": "upper(?)"},
        columns={"make_this_integer": int},
    )
    assert species.schema == (
        "CREATE TABLE [species] (\n"
        "   [renamed_id] INTEGER PRIMARY KEY,\n"
        "   [this_at_front] INTEGER,\n"
        "   [name] TEXT,\n"
        "   [type] TEXT,\n"
        "   [first_seen] TEXT,\n"
        "   [make_not_null] INTEGER NOT NULL,\n"
        "   [fk_to_other] INTEGER REFERENCES [other_table]([id]),\n"
        "   [default_is_dog] TEXT DEFAULT 'dog',\n"
        "   [extract_this] INTEGER REFERENCES [extract_this]([id]),\n"
        "   [convert_to_upper] TEXT,\n"
        "   [make_this_integer] INTEGER\n"
        ")"
    )
    assert species.get(id) == {
        "renamed_id": id,
        "this_at_front": 1,
        "name": "Palm",
        "type": "Tree",
        "first_seen": "2020-01-01",
        "make_not_null": 1,
        "fk_to_other": 1,
        "default_is_dog": "cat",
        "extract_this": 1,
        "convert_to_upper": "UPPER",
        "make_this_integer": 2,
    }
    assert species.indexes == [
        Index(
            seq=0,
            name="idx_species_name_type",
            unique=1,
            origin="c",
            partial=0,
            columns=["name", "type"],
        )
    ]


@pytest.mark.parametrize("strict", (False, True))
def test_lookup_new_table_strict(fresh_db, strict):
    fresh_db["species"].lookup({"name": "Palm"}, strict=strict)
    assert fresh_db["species"].strict == strict or not fresh_db.supports_strict
