import pytest

from helpers.cluster import ClickHouseCluster

cluster = ClickHouseCluster(__file__)
node = cluster.add_instance('node')
path_to_userfiles_from_defaut_config = "/var/lib/clickhouse/user_files/"   # should be the same as in config file

@pytest.fixture(scope="module")
def start_cluster():
    try:
        cluster.start()

        yield cluster

    except Exception as ex:
        print(ex)
        raise ex
    finally:
        cluster.shutdown()

def test_strange_filenames(start_cluster):
    # 2 rows data
    some_data = "\t111.222\nData\t333.444"

    node.exec_in_container(['bash', '-c', 'mkdir {}strange_names/'.format(path_to_userfiles_from_defaut_config)], privileged=True, user='root')

    files = ["p.o.i.n.t.s",
             "b}{ra{ces",
             "b}.o{t.h"]

    # filename inside testing data for debug simplicity
    for filename in files:
        node.exec_in_container(['bash', '-c', 'echo "{}{}" > {}strange_names/{}'.format(filename, some_data, path_to_userfiles_from_defaut_config, filename)], privileged=True, user='root')

    test_requests = [("p.o.??n.t.s", "2"),
                     ("p.o.*t.s", "2"),
                     ("b}{r?{ces", "2"),
                     ("b}*ces", "2"),
                     ("b}.?{t.h", "2")]

    for pattern, value in test_requests:
        assert node.query('''
            select count(*) from file('strange_names/{}', 'TSV', 'text String, number Float64')
        '''.format(pattern)) == '{}\n'.format(value)
        assert node.query('''
            select count(*) from file('{}strange_names/{}', 'TSV', 'text String, number Float64')
        '''.format(path_to_userfiles_from_defaut_config, pattern)) == '{}\n'.format(value)

def test_linear_structure(start_cluster):
    # 2 rows data
    some_data = "\t123.456\nData\t789.012"

    files = ["file1", "file2", "file3", "file4", "file5",
             "file000", "file111", "file222", "file333", "file444",
             "a_file", "b_file", "c_file", "d_file", "e_file",
             "a_data", "b_data", "c_data", "d_data", "e_data"]

    # filename inside testing data for debug simplicity
    for filename in files:
        node.exec_in_container(['bash', '-c', 'echo "{}{}" > {}{}'.format(filename, some_data, path_to_userfiles_from_defaut_config, filename)], privileged=True, user='root')

    test_requests = [("file{0..9}", "10"),
                     ("file?", "10"),
                     ("nothing*", "0"),
                     ("file{0..9}{0..9}{0..9}", "10"),
                     ("file{000..999}", "10"),
                     ("file???", "10"),
                     ("file*", "20"),
                     ("a_{file,data}", "4"),
                     ("?_{file,data}", "20"),
                     ("{a,b,c,d,e}_{file,data}", "20"),
                     ("{a,b,c,d,e}?{file,data}", "20"),
                     ("*", "40")]

    for pattern, value in test_requests:
        assert node.query('''
            select count(*) from file('{}', 'TSV', 'text String, number Float64')
        '''.format(pattern)) == '{}\n'.format(value)
        assert node.query('''
            select count(*) from file('{}{}', 'TSV', 'text String, number Float64')
        '''.format(path_to_userfiles_from_defaut_config, pattern)) == '{}\n'.format(value)

def test_deep_structure(start_cluster):
    # 2 rows data
    some_data = "\t135.791\nData\t246.802"
    dirs = ["directory1/", "directory2/", "some_more_dir/", "we/",
            "directory1/big_dir/",
            "directory1/dir1/", "directory1/dir2/", "directory1/dir3/",
            "directory2/dir1/", "directory2/dir2/", "directory2/one_more_dir/",
            "some_more_dir/yet_another_dir/",
            "we/need/", "we/need/to/", "we/need/to/go/", "we/need/to/go/deeper/"]

    for dir in dirs:
        node.exec_in_container(['bash', '-c', 'mkdir {}{}'.format(path_to_userfiles_from_defaut_config, dir)], privileged=True, user='root')

    # all directories appeared in files must be listed in dirs
    files = []
    for i in range(10):
        for j in range(10):
            for k in range(10):
                files.append("directory1/big_dir/file" + str(i) + str(j) + str(k))

    for dir in dirs:
        files.append(dir+"file")

    # filename inside testing data for debug simplicity
    for filename in files:
        node.exec_in_container(['bash', '-c', 'echo "{}{}" > {}{}'.format(filename, some_data, path_to_userfiles_from_defaut_config, filename)], privileged=True, user='root')

    test_requests = [ ("directory{1..5}/big_dir/*", "2002"), ("directory{0..6}/big_dir/*{0..9}{0..9}{0..9}", "2000"),
                     ("?", "0"),
                     ("directory{0..5}/dir{1..3}/file", "10"), ("directory{0..5}/dir?/file", "10"),
                     ("we/need/to/go/deeper/file", "2"), ("*/*/*/*/*/*", "2"), ("we/need/??/go/deeper/*?*?*?*?*", "2")]

    for pattern, value in test_requests:
        assert node.query('''
            select count(*) from file('{}', 'TSV', 'text String, number Float64')
        '''.format(pattern)) == '{}\n'.format(value)
        assert node.query('''
            select count(*) from file('{}{}', 'TSV', 'text String, number Float64')
        '''.format(path_to_userfiles_from_defaut_config, pattern)) == '{}\n'.format(value)

def test_table_function_and_virtual_columns(start_cluster):
    node.exec_in_container(['bash', '-c', 'mkdir -p {}some/path/to/'.format(path_to_userfiles_from_defaut_config)])
    node.exec_in_container(['bash', '-c', 'touch {}some/path/to/data.CSV'.format(path_to_userfiles_from_defaut_config)])
    node.query("insert into table function file('some/path/to/data.CSV', CSV, 'n UInt8, s String') select number, concat('str_', toString(number)) from numbers(100000)")
    assert node.query("select count() from file('some/path/to/data.CSV', CSV, 'n UInt8, s String')").rstrip() == '100000'
    node.query("insert into table function file('nonexist.csv', 'CSV', 'val1 UInt32') values (1)")
    assert node.query("select * from file('nonexist.csv', 'CSV', 'val1 UInt32')").rstrip()== '1'
    assert "nonexist.csv" in node.query("select _path from file('nonexis?.csv', 'CSV', 'val1 UInt32')").rstrip()
    assert "nonexist.csv" in node.query("select _path from file('nonexist.csv', 'CSV', 'val1 UInt32')").rstrip()
    assert "nonexist.csv" == node.query("select _file from file('nonexis?.csv', 'CSV', 'val1 UInt32')").rstrip()
    assert "nonexist.csv" == node.query("select _file from file('nonexist.csv', 'CSV', 'val1 UInt32')").rstrip()