#!/usr/bin/env python3
import os

from cli_tests import console
from cli_tests.test_turso_cli import TestTursoShell
from pydantic import BaseModel

sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ")


class CollateTest(BaseModel):
    name: str
    db_schema: str = """CREATE TABLE t1(
        x INTEGER PRIMARY KEY,
        a,                 /* collating sequence BINARY */
        b COLLATE BINARY,  /* collating sequence BINARY */
        c COLLATE RTRIM,   /* collating sequence RTRIM  */
        d COLLATE NOCASE   /* collating sequence NOCASE */
    );"""
    db_path: str = "testing/collate.db"

    def init_db(self):
        with TestTursoShell(
            init_commands="",
            exec_name="sqlite3",
            flags=f"{self.db_path}",
        ) as sqlite:
            sqlite.execute_dot(f".open {self.db_path}")
            stmt = [self.db_schema]
            stmt = stmt + [
                "INSERT INTO t1 VALUES(1,'abc','abc', 'abc  ','abc');",
                "INSERT INTO t1 VALUES(2,'abc','abc', 'abc',  'ABC');",
                "INSERT INTO t1 VALUES(3,'abc','abc', 'abc ', 'Abc');",
                "INSERT INTO t1 VALUES(4,'abc','abc ','ABC',  'abc');",
            ]
            stmt.append("SELECT count(*) FROM t1;")

            sqlite.run_test(
                "Init Collate Db in Sqlite",
                "".join(stmt),
                f"{4}",
            )

    def run(self, limbo: TestTursoShell):
        limbo.execute_dot(f".open {self.db_path}")

        limbo.run_test(
            "Text comparison a=b is performed using the BINARY collating sequence",
            "SELECT x FROM t1 WHERE a = b ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 2, 3])),
        )

        limbo.run_test(
            "Text comparison a=b is performed using the RTRIM collating sequence",
            "SELECT x FROM t1 WHERE a = b COLLATE RTRIM ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 2, 3, 4])),
        )

        limbo.run_test(
            "Text comparison d=a is performed using the NOCASE collating sequence",
            "SELECT x FROM t1 WHERE d = a ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 2, 3, 4])),
        )

        limbo.run_test(
            "Text comparison a=d is performed using the BINARY collating sequence.",
            "SELECT x FROM t1 WHERE a = d ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 4])),
        )

        limbo.run_test(
            "Text comparison 'abc'=c is performed using the RTRIM collating sequence.",
            "SELECT x FROM t1 WHERE 'abc' = c ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 2, 3])),
        )

        limbo.run_test(
            "Text comparison c='abc' is performed using the RTRIM collating sequence.",
            "SELECT x FROM t1 WHERE c = 'abc' ORDER BY x;",
            "\n".join(map(lambda x: str(x), [1, 2, 3])),
        )

        limbo.run_test(
            "Grouping is performed using the NOCASE collating sequence (Values 'abc', 'ABC', and 'Abc' are placed in the same group).",  # noqa: E501
            "SELECT count(*) FROM t1 GROUP BY d ORDER BY 1;",
            "\n".join(map(lambda x: str(x), [4])),
        )

        limbo.run_test(
            "Grouping is performed using the BINARY collating sequence. 'abc' and 'ABC' and 'Abc' form different groups",  # noqa: E501
            "SELECT count(*) FROM t1 GROUP BY (d || '') ORDER BY 1;",
            "\n".join(map(lambda x: str(x), [1, 1, 2])),
        )

        limbo.run_test(
            "Sorting or column c is performed using the RTRIM collating sequence.",
            "SELECT x FROM t1 ORDER BY c, x;",
            "\n".join(map(lambda x: str(x), [4, 1, 2, 3])),
        )

        limbo.run_test(
            "Sorting of (c||'') is performed using the BINARY collating sequence.",
            "SELECT x FROM t1 ORDER BY (c||''), x;",
            "\n".join(map(lambda x: str(x), [4, 2, 3, 1])),
        )

        limbo.run_test(
            "Sorting of column c is performed using the NOCASE collating sequence.",
            "SELECT x FROM t1 ORDER BY c COLLATE NOCASE, x;",
            "\n".join(map(lambda x: str(x), [2, 4, 3, 1])),
        )


def cleanup(db_fullpath: str):
    wal_path = f"{db_fullpath}-wal"
    shm_path = f"{db_fullpath}-shm"
    paths = [db_fullpath, wal_path, shm_path]
    for path in paths:
        if os.path.exists(path):
            os.remove(path)


def main():
    # Test from using examples from Section 7.2
    # https://sqlite.org/datatype3.html#collation
    test = CollateTest(name="Smoke collate tests")
    console.info(test)

    db_path = test.db_path
    try:
        test.init_db()
        # Use with syntax to automatically close shell on error
        with TestTursoShell("") as limbo:
            test.run(limbo)

        # test.test_compat()
    except Exception as e:
        console.error(f"Test FAILED: {e}")
        cleanup(db_path)
        exit(1)
    # delete db after every compat test so we we have fresh db for next test
    cleanup(db_path)
    console.info("All tests passed successfully.")


if __name__ == "__main__":
    main()
