#
# Copyright (c) Daniel Sheffield 2023
#
# All rights reserved
#
# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
from psycopg.sql import SQL, Literal, Composable
from typing import Callable, Iterable, Union
from pytest import mark, raises
from app.data.util import (
    get_where_include_exclude,
    get_select,
    get_from,
    get_groupby,
)

@mark.parametrize('table', [
    'table',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
@mark.parametrize('col', [
    'column',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
@mark.parametrize('include', [
    [],
    ['inc-a', ],
    ['inc-a', 'inc-b'],
    None, # TODO: check this
    '', # TODO: check this
])
@mark.parametrize('exclude', [
    [],
    ['exc-a', ],
    ['exc-a', 'exc-b'],
    None, # TODO: check this
    '', # TODO: check this
])
def test_get_where_include_exclude(
        table: str,
        col: str,
        include: Iterable[str],
        exclude: Iterable[str]
) -> None:
    exp_exceptions = [
        ex for arg, ex, msg in map(
            lambda x: x if isinstance(x, tuple) else (x, None, None),
            (table, col, include, exclude)
        ) if ex is not None
    ]

    if not exp_exceptions:
        assert get_where_include_exclude(table, col, include, exclude) is not None
        return

    with raises(tuple(exp_exceptions)):
        get_where_include_exclude(table, col, include, exclude)


@mark.parametrize('composable', [
    SQL('1'),
    Literal(1),
    None,
])
@mark.parametrize('alias', [
    'alias',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
def test_get_select(composable: Composable, alias: str) -> None:
    exp_exceptions = [
        ex for arg, ex, msg in map(
            lambda x: x if isinstance(x, tuple) else (x, None, None),
            (composable, alias)
        ) if ex is not None
    ]

    if not exp_exceptions:
        assert get_select({ alias: composable }) is not None
        return

    with raises(tuple(exp_exceptions)):
        get_select({ alias: composable })

@mark.parametrize('base', [
    'base',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
@mark.parametrize('table', [
    'table',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
@mark.parametrize('on_column', [
    'column',
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
])
@mark.parametrize('left_hand_column', [
    'id',
    ('l', 'id'),
    (None, TypeError, "Identifier cannot be empty"),
    ('', TypeError, "Identifier cannot be empty"),
    (('', None), TypeError, "Identifier cannot be empty"),
    (('l', ''), TypeError, "Identifier cannot be empty"),
])
def test_get_from(
    base: str,
    table: str, on_column: str,
    left_hand_column: Union[Iterable, str]) -> Composable:
    exp_exceptions = [
        ex for arg, ex, msg in map(
            lambda x: x if isinstance(x, tuple) and len(x) == 3 else (x, None, None),
            (base, table, on_column, left_hand_column)
        ) if ex is not None
    ]

    if not exp_exceptions:
        assert get_from(base, { table: (on_column, left_hand_column) }) is not None
        return

    with raises(tuple(exp_exceptions)):
        get_from(base, { table: (on_column, left_hand_column) })

@mark.parametrize('composable', [
    SQL('1'),
    Literal(1),
    None,
])
# TODO: unused param
@mark.parametrize('alias', [
    'alias',
    None,
    '',
])
@mark.parametrize('formatter', [
    lambda x: x,
    None,
])
def test_get_groupby(composable: Composable, alias: str, formatter: Callable[[SQL], Composable]) -> None:
    exp_exceptions = [
        ex for arg, ex, msg in map(
            lambda x: x if isinstance(x, tuple) else (x, None, None),
            (composable, alias)
        ) if ex is not None
    ]

    if not exp_exceptions:
        assert get_groupby({ alias: composable }) is not None
        return

    with raises(tuple(exp_exceptions)):
        get_groupby({ alias: composable }, formatter=formatter)


