import unittest

from pydal import DAL, Field
from pydal.validators import IS_NOT_IN_DB
from pydal.restapi import RestAPI, ALLOW_ALL_POLICY, DENY_ALL_POLICY, __version__


class TestRestAPI(unittest.TestCase):
    def setUp(self):
        db = DAL("sqlite:memory")

        db.define_table("color", Field("name", requires=IS_NOT_IN_DB(db, "color.name")))
        db.color.insert(name="red")
        db.color.insert(name="green")
        db.color.insert(name="blue")

        db.define_table("thing", Field("name"), Field("color", "reference color"))
        db.thing.insert(name="Chair", color=1)
        db.thing.insert(name="Chair", color=2)
        db.thing.insert(name="Table", color=1)
        db.thing.insert(name="Table", color=3)
        db.thing.insert(name="Lamp", color=2)

        db.define_table(
            "rel",
            Field("a", "reference thing"),
            Field("desc"),
            Field("b", "reference thing"),
        )
        db.rel.insert(a=1, b=2, desc="is like")
        db.rel.insert(a=3, b=4, desc="is like")
        db.rel.insert(a=1, b=3, desc="is under")
        db.rel.insert(a=2, b=4, desc="is under")
        db.rel.insert(a=5, b=4, desc="is above")

        api = RestAPI(db, ALLOW_ALL_POLICY)

        self.db = db
        self.api = api

    def test_search(self):
        api = self.api
        api.policy = ALLOW_ALL_POLICY

        self.assertEqual(
            api.search("rel", {"@limit": 0, "@model": "true"}),
            {
                "items": [],
                "count": 5,
                "model": [
                    {
                        "name": "id",
                        "label": "Id",
                        "default": None,
                        "type": "id",
                        "regex": "[1-9]\\d*",
                        "required": False,
                        "unique": False,
                        "post_writable": True,
                        "put_writable": True,
                        "options": None,
                        "referenced_by": [],
                    },
                    {
                        "name": "a",
                        "label": "A",
                        "default": None,
                        "type": "reference",
                        "references": "thing",
                        "regex": None,
                        "required": False,
                        "unique": False,
                        "post_writable": True,
                        "put_writable": True,
                        "options": None,
                    },
                    {
                        "name": "desc",
                        "label": "Desc",
                        "default": None,
                        "type": "string",
                        "regex": None,
                        "required": False,
                        "unique": False,
                        "post_writable": True,
                        "put_writable": True,
                        "options": None,
                    },
                    {
                        "name": "b",
                        "label": "B",
                        "default": None,
                        "type": "reference",
                        "references": "thing",
                        "regex": None,
                        "required": False,
                        "unique": False,
                        "post_writable": True,
                        "put_writable": True,
                        "options": None,
                    },
                ],
            },
        )
        self.assertEqual(
            api.search("color", {"name.eq": "red"}),
            {"count": 1, "items": [{"id": 1, "name": "red"}]},
        )
        self.assertEqual(
            api.search("thing", {"name.eq": "Chair"}),
            {
                "count": 2,
                "items": [
                    {"name": "Chair", "color": 1, "id": 1},
                    {"name": "Chair", "color": 2, "id": 2},
                ],
            },
        )
        self.assertEqual(
            api.search("rel[a,b]", {"desc.eq": "is like"}),
            {"count": 2, "items": [{"b": 2, "a": 1}, {"b": 4, "a": 3}]},
        )
        self.assertEqual(
            api.search("thing[name]", {"color.name.eq": "red"}),
            {"count": 2, "items": [{"name": "Chair"}, {"name": "Table"}]},
        )
        self.assertEqual(
            api.search("thing[name]", {"not.color.name.eq": "red"}),
            {
                "count": 3,
                "items": [{"name": "Chair"}, {"name": "Table"}, {"name": "Lamp"}],
            },
        )
        self.assertEqual(
            api.search("thing[name]", {"a.rel.desc": "is above"}),
            {"count": 1, "items": [{"name": "Lamp"}]},
        )
        self.assertEqual(
            api.search("thing[name]", {"a.rel.b.name": "Table"}),
            {
                "count": 4,
                "items": [
                    {"name": "Chair"},
                    {"name": "Chair"},
                    {"name": "Table"},
                    {"name": "Lamp"},
                ],
            },
        )
        self.assertEqual(
            api.search(
                "thing[name]", {"a.rel.b.name": "Table", "a.rel.desc": "is above"}
            ),
            {"count": 1, "items": [{"name": "Lamp"}]},
        )
        self.assertEqual(
            api.search("thing", {"@lookup": "color"}),
            {
                "count": 5,
                "items": [
                    {"name": "Chair", "color": {"name": "red", "id": 1}, "id": 1},
                    {"name": "Chair", "color": {"name": "green", "id": 2}, "id": 2},