import sqlite3
from collections import defaultdict
from pathlib import Path
from utils.protein_group_sql_db import ProteinGroupSqlDbInteractor

# script with functions used for updating the test databases
# from pg_yaml to first version of the protein group sql db
# from database version 1 (all information in one table) to 2 (separate table for proteins
# and from version 2 to 3 (separate table for sample names)
# functions for printing sql-databases

# all test dbs that need to be changed in case of db schema update
paths_to_sql_dbs_in_tests = [
    "tests/integration_tests/mztab_parser/expected_results/pd_example_pg_db.sql",
    "tests/integration_tests/pd_parser/expected_results/result1_protein_groups_db.sql",
    "tests/integration_tests/pd_parser/expected_results/result2_protein_groups_db.sql",
    "tests/integration_tests/pd_parser/expected_results/protein_groups_error_test_db.sql",
    "tests/integration_tests/mztab_parser/expected_results/maxquant_pg_db.sql",
    "tests/integration_tests/weighted_lca/resources/job_resources/protein_groups_db.sql",
    "tests/integration_tests/weighted_lca/resources/job_resources_with_spectra/protein_groups_db_with_spectra.sql",
    "tests/unit_tests/conversion_pg_yaml_to_sql_db/expected_results/protein_groups_db_without_spectra.sql",
    "tests/unit_tests/conversion_pg_yaml_to_sql_db/expected_results/protein_groups_db_with_spectra.sql",
    "tests/integration_tests/read_spectra_from_db/protein_groups_db.sql",
    "tests/resources/test_full_analysis_and_file_presence/expected-results/pgs/protein_groups_db.sql",
    "tests/resources/test_full_analysis_dryrun_wo_sample_groups/expected-results/pgs/protein_groups_db.sql",
    "tests/resources/test_lca_on_maps_with_spectra/job_dir/pgs/protein_groups_db.sql",
    "tests/resources/test_summary_on_maps_with_spectra/job_dir/pgs/protein_groups_db.sql",

]
# for update database schema:
# names for new databases, changed to old names, if all information from old databases are transferred
paths_to_new_sql_dbs_in_tests = [paths_to_sql_db.split('.sql')[0] + '_new.sql' for paths_to_sql_db in paths_to_sql_dbs_in_tests]


def create_connection(path_to_pg_db):
    conn = None
    try:
        conn = sqlite3.connect(path_to_pg_db)
    except Exception as e:
        print(f"Exception: {e} caused by file {path_to_pg_db}")
        exit(1)
    return conn


def create_protein_group_quant_table_version2(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinGroupsQuant
     (ID INT NOT NULL,
     quant FLOAT NOT NULL,
     spectra varchar, 
     sample varchar NOT NULL,
     PRIMARY KEY (ID, sample));''')
    conn.close()

def create_protein_group_quant_table_version3(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinGroupsQuant
     (ID INT NOT NULL,
     quant FLOAT NOT NULL,
     spectra varchar, 
     sample_id INT NOT NULL,
     PRIMARY KEY (ID, sample_id));''')
    conn.close()

def create_protein_group_quant_table_version4(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinGroupsQuant
     (ID INT NOT NULL,
     quant FLOAT NOT NULL,
     sample_id INT NOT NULL,
     PRIMARY KEY (ID, sample_id));''')
    conn.close()

def create_protein_sample_table_version3(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE SAMPLES
     (sample_id INT PRIMARY KEY NOT NULL,
     sample_name varchar);''')
    conn.close()

def create_protein_sample_table_version4(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE SAMPLES
         (sample_id INT PRIMARY KEY NOT NULL,
         sample_name varchar NOT NULL,
         sample_group varchar);''')
    conn.close()

def create_protein_group_proteins_table_version2(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinGroupsProteins
     (ID INT PRIMARY KEY NOT NULL,
     proteins varchar NOT NULL);''')
    conn.close()


def create_protein_information_table(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinGroupsInformation
             (ID varchar(20) PRIMARY KEY NOT NULL,
             information varchar NOT NULL);''')
    conn.close()


def create_protein_accs_spectra_table_version4(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    conn.execute('''CREATE TABLE ProteinAccSpectra
         (pgid INT NOT NULL,
         acc varchar,
         spectra varchar, 
         sample_id INT NOT NULL,
         PRIMARY KEY (pgid, acc, sample_id));''')
    conn.close()

def insert_into_protein_group_tables_version2(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                    records_to_insert_into_quant_table):
    sqlite_insert_query = """INSERT INTO ProteinGroupsProteins
                          (ID,proteins) 
                          VALUES (?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_proteins_table)

    if with_spectra:
        sqlite_insert_query = """INSERT INTO ProteinGroupsQuant
                          (ID,quant,spectra, sample) 
                          VALUES (?, ?, ?, ?);"""
    else:
        sqlite_insert_query = """INSERT INTO ProteinGroupsQuant
                          (ID,quant,sample) 
                          VALUES (?, ?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_quant_table)
    conn.commit()

def insert_into_protein_group_tables_version3(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                              records_to_insert_into_quant_table):
    sqlite_insert_query = """INSERT INTO ProteinGroupsProteins
                          (ID,proteins) 
                          VALUES (?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_proteins_table)

    if with_spectra:
        sqlite_insert_query = """INSERT INTO ProteinGroupsQuant
                          (ID,quant,spectra, sample_id) 
                          VALUES (?, ?, ?, ?);"""
    else:
        sqlite_insert_query = """INSERT INTO ProteinGroupsQuant
                          (ID,quant,sample_id) 
                          VALUES (?, ?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_quant_table)
    conn.commit()


def insert_into_protein_group_tables_version4(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                              records_to_insert_into_quant_table, records_to_insert_into_spectra_table):
    sqlite_insert_query = """INSERT INTO ProteinGroupsProteins
                              (ID,proteins) 
                              VALUES (?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_proteins_table)

    sqlite_insert_query = """INSERT INTO ProteinGroupsQuant
                              (ID,quant,sample_id) 
                              VALUES (?, ?, ?);"""
    cursor.executemany(sqlite_insert_query, records_to_insert_into_quant_table)
    if with_spectra:
        sqlite_insert_query = """INSERT INTO ProteinAccSpectra
                                  (pgid,acc,spectra,sample_id) 
                                  VALUES (?, ?, ?, ?);"""
        cursor.executemany(sqlite_insert_query, records_to_insert_into_spectra_table)
    conn.commit()


def fill_pg_tables_version2(path_to_pg_db, list_of_pg_dict, sample_list, with_spectra):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    records_to_insert_into_quant_table = []
    records_to_insert_into_proteins_table = []
    for pg_nb, pg in enumerate(list_of_pg_dict):
        accs = pg['proteins']
        records_to_insert_into_proteins_table.append((pg_nb, accs))
        for i, sample in enumerate(sample_list):
            quant = pg['quant'][i]
            if with_spectra:
                spectra = pg['spectra'][i]
                records_to_insert_into_quant_table.append((pg_nb, quant, spectra, sample))
            else:
                records_to_insert_into_quant_table.append((pg_nb, quant, sample))
            if len(records_to_insert_into_proteins_table) > 499:
                insert_into_protein_group_tables_version2(conn, cursor, with_spectra,
                                                          records_to_insert_into_proteins_table,
                                                          records_to_insert_into_quant_table)
                records_to_insert_into_proteins_table,  records_to_insert_into_quant_table = [], []
    insert_into_protein_group_tables_version2(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                              records_to_insert_into_quant_table)
    conn.close()


def fill_pg_tables_version3(path_to_pg_db, list_of_pg_dict, sample_list, with_spectra):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    records_to_insert_into_quant_table = []
    records_to_insert_into_proteins_table = []
    for pg_nb, pg in enumerate(list_of_pg_dict):
        accs = pg['proteins']
        records_to_insert_into_proteins_table.append((pg_nb, accs))
        for i, sample in enumerate(sample_list):
            quant = pg['quant'][i]
            if with_spectra:
                spectra = pg['spectra'][i]
                records_to_insert_into_quant_table.append((pg_nb, quant, spectra, i))
            else:
                records_to_insert_into_quant_table.append((pg_nb, quant, i))
            if len(records_to_insert_into_proteins_table) > 499:
                insert_into_protein_group_tables_version3(conn, cursor, with_spectra,
                                                          records_to_insert_into_proteins_table,
                                                          records_to_insert_into_quant_table)
                records_to_insert_into_proteins_table,  records_to_insert_into_quant_table = [], []
    insert_into_protein_group_tables_version3(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                              records_to_insert_into_quant_table)
    conn.close()


def get_spectra_as_list(spectra_from_pg_and_sample, accs_nb, protein_sep):
    spectra_list = spectra_from_pg_and_sample.split(f']{protein_sep}[')
    if spectra_list == ['[[]]'] or spectra_list == [''] or spectra_list == ['-']:
        spectra_list = [None] * accs_nb
    else:
        for i, spectra_str in enumerate(spectra_list):
            while spectra_str.startswith('['):
                spectra_str = spectra_str[1:]
            while spectra_str.endswith(']'):
                spectra_str = spectra_str[:-1]
            spectra_list[i] = spectra_str
        # None for no spectra
        spectra_list = [None if spectra == '' else spectra for spectra in spectra_list]
        # remove " and ' from spectra string
        spectra_list = [spectra.replace("'", "").replace('"', "") if spectra is not None else None for spectra in spectra_list ]
    return spectra_list


def fill_pg_tables_version4(path_to_pg_db, list_of_pg_dict, sample_list, protein_sep, with_spectra):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    records_to_insert_into_quant_table = []
    records_to_insert_into_proteins_table = []
    records_to_insert_into_spectra_table = []
    for pgid, pg in enumerate(list_of_pg_dict):
        accs_str = pg['proteins']
        if with_spectra:
            accs = accs_str.split(protein_sep)
        records_to_insert_into_proteins_table.append((pgid, accs_str))
        for sample_id in range(len(sample_list)):
            quant = pg['quant'][sample_id]
            records_to_insert_into_quant_table.append((pgid, quant, sample_id))
            if with_spectra:
                spectra_list = get_spectra_as_list(pg['spectra'][sample_id], len(accs), protein_sep)
                for i, acc in enumerate(accs):
                    records_to_insert_into_spectra_table.append((pgid, acc, spectra_list[i], sample_id))
            if len(records_to_insert_into_proteins_table) > 499:
                insert_into_protein_group_tables_version4(conn, cursor, with_spectra,
                                                      records_to_insert_into_proteins_table,
                                                      records_to_insert_into_quant_table,
                                                      records_to_insert_into_spectra_table)
                records_to_insert_into_proteins_table,  records_to_insert_into_quant_table, \
                records_to_insert_into_spectra_table = [], [], []
    insert_into_protein_group_tables_version4(conn, cursor, with_spectra, records_to_insert_into_proteins_table,
                                          records_to_insert_into_quant_table, records_to_insert_into_spectra_table)
    conn.close()


def fill_pg_info_table(path_to_pg_db, protein_info_data):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
        VALUES ('protein_sep', '{protein_info_data['protein_sep']}');")
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
            VALUES ('quant_type', '{protein_info_data['quant_type']}');")
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
            VALUES ('with_spectra', '{protein_info_data['with_spectra']}');")
    conn.commit()
    conn.close()


def fill_pg_info_table_version_4(path_to_pg_db, protein_info_data):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
        VALUES ('protein_sep', '{protein_info_data['protein_sep']}');")
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
            VALUES ('quant_type', '{protein_info_data['quant_type']}');")
    cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
            VALUES ('with_spectra', '{protein_info_data['with_spectra']}');")
    cursor.execute("INSERT INTO ProteinGroupsInformation (ID,information)"
                   " VALUES ('db_schema_version', 4);")
    conn.commit()
    conn.close()


def fill_samples_table(path_to_pg_db, sample_list):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    for id, name in enumerate(sample_list):
        cursor.execute(f"INSERT INTO Samples (sample_id,sample_name) \
            VALUES ('{id}', '{name}');")
    conn.commit()
    conn.close()


def get_pg_information(path_to_pg_db):
    inf_dict = {}
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"SELECT * from ProteinGroupsInformation;")
    rows = cursor.fetchall()
    for row in rows:
        inf_dict[row[0]] = row[1]
    conn.close()
    return inf_dict


def get_pgs_from_db_version1(path_to_pg_db, pg_list=None, information_type=None):
    """
    :param pg_list: list of selected protein group IDs, if None -> select all
    :param information_type: list of strings of selected informations (choose from 'proteins', 'quant', 'spectra',
    'sample'),  default: all information
    return pg_dict[pg_id]=[{'proteins': accs_str,  'quant': float, 'spectra': spectra_id_str, 'sample': str}, {}]
    """
    if information_type is None:
        information_type = ['proteins', 'quant', 'spectra', 'sample']
    pg_dict=defaultdict(list)
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    if pg_list:
        select_str = f"SELECT DISTINCT {'id, ' + ','.join(information_type)} from ProteinGroups WHERE ID IN " \
                     f"({','.join([str(pg) for pg in pg_list])});"
    else:
        select_str = f"SELECT DISTINCT {'id, ' + ','.join(information_type)} from ProteinGroups;"
    cursor.execute(select_str)
    rows = cursor.fetchall()
    for row in rows:
        pg_sample_dict = {}
        for i, information in enumerate(information_type):
            pg_sample_dict[information] = row[i+1]
        pg_dict[row[0]].append(pg_sample_dict)
    conn.close()
    return pg_dict


def get_pgs_from_db_version2(path_to_pg_db, pg_list=None, information_type=None):
    if information_type is None:
        information_type = ['proteins', 'quant', 'spectra', 'sample']
    pg_dict=defaultdict(list)
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    selected_ids_string = f" WHERE ID IN ({','.join([str(pg) for pg in pg_list])});" if pg_list else ";"
    if information_type == ['proteins']:
        select_str = f"SELECT DISTINCT {'id, proteins'} from ProteinGroupsProteins " + selected_ids_string
    elif 'proteins' in information_type and len(information_type) > 1:
        selected_ids_string = f" WHERE ProteinGroupsProteins.ID IN ({','.join([str(pg) for pg in pg_list])});" if pg_list else ";"
        select_str = f"SELECT DISTINCT {'ProteinGroupsProteins.id AS ID, ' + ', '.join(information_type)} from ProteinGroupsQuant INNER Join " \
                     f"ProteinGroupsProteins ON ProteinGroupsProteins.id = ProteinGroupsQuant.id" + selected_ids_string
    elif 'proteins' not in information_type:
        select_str = f"SELECT DISTINCT {'ID, ' + ', '.join(information_type)} from ProteinGroupsQuant " \
                     + selected_ids_string
    cursor.execute(select_str)
    rows = cursor.fetchall()
    for row in rows:
        pg_sample_dict = {}
        for i, information in enumerate(information_type):
            pg_sample_dict[information] = row[i+1]
        pg_dict[row[0]].append(pg_sample_dict)
    conn.close()
    return pg_dict


def get_pg_id_to_accs_dict_from_version3(path_to_pd, pg_list=None):
    conn = create_connection(path_to_pd)
    cursor = conn.cursor()
    selected_ids_part = f" WHERE ID IN ({','.join([str(pg) for pg in pg_list])});" if pg_list else ";"
    cursor.execute(f"SELECT * from ProteinGroupsProteins " + selected_ids_part)
    rows = cursor.fetchall()
    pg_dict = {row[0]: row[1] for row in rows}
    conn.close()
    return pg_dict


def get_protein_group_quant_data_from_version3(path_to_pd, pg_list=None, information_type=None):
    """
        :param pg_list: list of selected protein group IDs, if None -> select all
        :param information_type: list of strings of selected informations (choose from 'proteins', 'quant', 'spectra',
        'sample'),  default: all information
        return pg_dict[pg_id]=[{'proteins': accs_str,  'quant': float, 'spectra': spectra_id_str, 'sample': str}, {}]
        """
    if information_type is None:
        information_type = ['proteins', 'quant', 'spectra']
    conn = create_connection(path_to_pd)
    cursor = conn.cursor()
    if 'proteins' in information_type:
        select_part =  f"SELECT DISTINCT {'ProteinGroupsProteins.id AS ID, sample_name, ' + ', '.join(information_type)} from ProteinGroupsProteins "
        selected_ids_part = f" WHERE ProteinGroupsProteins.ID IN ({','.join([str(pg) for pg in pg_list])});" if pg_list else ";"
        protein_join_part = f"INNER Join ProteinGroupsProteins ON ProteinGroupsProteins.id = ProteinGroupsQuant.id "
    else:
        select_part =  f"SELECT DISTINCT {'ProteinGroupsQuant.id AS ID, sample_name, ' + ', '.join(information_type)} from ProteinGroupsQuant "
        selected_ids_part = f" WHERE ProteinGroupsQuant.ID IN ({','.join([str(pg) for pg in pg_list])});" if pg_list else ";"
        protein_join_part = " "
    sample_join_part = f"INNER Join Samples ON ProteinGroupsQuant.sample_id = Samples.sample_id "

    if information_type == ['proteins']:
        select_str = f"SELECT DISTINCT * from ProteinGroupsProteins " + selected_ids_part
    else:
        select_str = select_part + protein_join_part + sample_join_part + selected_ids_part
    cursor.execute(select_str)
    rows = cursor.fetchall()
    conn.close()
    return rows


def get_pg_information_from_version3(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"SELECT * from ProteinGroupsInformation;")
    rows = cursor.fetchall()
    inf_dict = {row[0]: row[1] for row in rows}
    conn.close()
    return inf_dict


def get_pgs_from_db_version3(path_to_pg_db, pgid_list=None, information_type=None):
    rows_quant = get_protein_group_quant_data_from_version3(path_to_pg_db, pgid_list, ['quant', 'spectra'])
    # rows_proteins: ['id', 'protein_accs_str']
    pg_id_to_accs_dict = get_pg_id_to_accs_dict_from_version3(path_to_pg_db, pgid_list)
    protein_groups_list = []
    with_spectra = True if get_pg_information_from_version3(path_to_pg_db)['with_spectra']=='True' else False
    for pgid in range(0, max(pg_id_to_accs_dict.keys())+1):
        all_rows_of_pgid = [row for row in rows_quant if row[0] == pgid]
        pg_dict = defaultdict(list)
        pg_dict['proteins'] = pg_id_to_accs_dict[pgid]
        for row in all_rows_of_pgid:
            pg_dict['quant'].append(row[2])
            if with_spectra:
                pg_dict['spectra'].append(row[3])
        protein_groups_list.append(pg_dict)
    return protein_groups_list


def get_samples_from_version1(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"SELECT DISTINCT (sample) from ProteinGroups;")
    rows = cursor.fetchall()
    samples = [row[0] for row in rows]
    conn.close()
    return samples


def get_samples_from_version2(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"SELECT DISTINCT (sample) from ProteinGroupsQuant;")
    rows = cursor.fetchall()
    samples = [row[0] for row in rows]
    conn.close()
    return samples


def get_samples_from_version3(path_to_pg_db):
    conn = create_connection(path_to_pg_db)
    cursor = conn.cursor()
    cursor.execute(f"SELECT DISTINCT (sample_name) from SAMPLES;")
    rows = cursor.fetchall()
    samples = [row[0] for row in rows]
    conn.close()
    return samples


def get_protein_groups_dict_from_db(pg_db, pgid_list=None, information_type=None):
    # from version 1 !!!
    # all_pg_dict = get_pgs_from_db_version1(pg_db, pgid_list, information_type)
    # from version2
    all_pg_dict = get_pgs_from_db_version2(pg_db, pgid_list, information_type)
    protein_groups_dict = []
    with_spectra = True if 'spectra' in all_pg_dict[0][0].keys() else False
    for pgid in range(0, max(all_pg_dict.keys())+1):
        pg_dict = defaultdict(list)
        pg_dict['proteins'] = all_pg_dict[pgid][0]['proteins']
        for elem in all_pg_dict[pgid]:
            pg_dict['quant'].append(elem['quant'])
            if with_spectra:
                pg_dict['spectra'].append(elem['spectra'])
        protein_groups_dict.append(pg_dict)
        del all_pg_dict[pgid]
    return protein_groups_dict


def get_protein_groups_dict_from_db_version3(pg_db, pgid_list=None):
    rows_quant = get_protein_group_quant_data_from_version3(pg_db, pgid_list, ['quant', 'spectra'])
    # rows_proteins: ['id', 'protein_accs_str']
    pg_id_to_accs_dict = get_pg_id_to_accs_dict_from_version3(pg_db, pgid_list)
    protein_groups_list = []
    with_spectra = True if get_pg_information(pg_db)['with_spectra'] == 'True' else False
    for pgid in range(0, max(pg_id_to_accs_dict.keys())+1):
        all_rows_of_pgid = [row for row in rows_quant if row[0] == pgid]
        pg_dict = defaultdict(list)
        pg_dict['proteins'] = pg_id_to_accs_dict[pgid]
        for row in all_rows_of_pgid:
            pg_dict['quant'].append(row[2])
            if with_spectra:
                pg_dict['spectra'].append(row[3])
        protein_groups_list.append(pg_dict)
    return protein_groups_list


def update_database_from_version1_to_version2(old_path, new_path):
    # for db version 1 to db version 2
    dict_pgs = get_protein_groups_dict_from_db(old_path)
    sample_list = get_samples_from_version1(old_path)
    with_spectra = True if get_pg_information(old_path)['with_spectra'] == 'True' else False
    create_protein_group_quant_table_version2(new_path)
    create_protein_group_proteins_table_version2(new_path)
    fill_pg_tables_version2(new_path, dict_pgs, sample_list, with_spectra)

    protein_info_data = get_pg_information(old_path)
    create_protein_information_table(new_path)
    fill_pg_info_table(new_path, protein_info_data)


def update_database_from_version2_to_version3(old_path, new_path):
    # for db version 2 to db version 3
    dict_pgs = get_protein_groups_dict_from_db(old_path)
    sample_list = get_samples_from_version2(old_path)
    with_spectra = True if get_pg_information(old_path)['with_spectra'] == 'True' else False
    create_protein_group_quant_table_version3(new_path)
    create_protein_group_proteins_table_version2(new_path)
    fill_pg_tables_version3(new_path, dict_pgs, sample_list, with_spectra)

    create_protein_sample_table_version3(new_path)
    fill_samples_table(new_path, sample_list)

    protein_info_data = get_pg_information(old_path)
    create_protein_information_table(new_path)
    fill_pg_info_table(new_path, protein_info_data)


def update_database_from_version3_to_version4(old_path, new_path):
    # for db version 3 to db version 4
    dict_pgs = get_protein_groups_dict_from_db_version3(old_path)
    sample_list = get_samples_from_version3(old_path)
    with_spectra = True if get_pg_information(old_path)['with_spectra'] == 'True' else False
    protein_sep = get_pg_information(old_path)['protein_sep']
    create_protein_group_quant_table_version4(new_path)
    create_protein_group_proteins_table_version2(new_path)
    create_protein_accs_spectra_table_version4(new_path)

    fill_pg_tables_version4(new_path, dict_pgs, sample_list, protein_sep, with_spectra)
    create_protein_information_table(new_path)

    create_protein_sample_table_version4(new_path)
    protein_info_data = get_pg_information(old_path)
    fill_pg_info_table_version_4(new_path, protein_info_data)
    fill_samples_table(new_path, sample_list)


def update_all_test_databases():
    for old_path, new_path in zip(paths_to_sql_dbs_in_tests, paths_to_new_sql_dbs_in_tests):
        print(old_path)
        update_database_from_version3_to_version4(old_path, new_path)
        Path(old_path).unlink()
        Path(new_path).rename(old_path)


def convert_yaml_to_db(path_to_yaml):
    sql_obj = ProteinGroupSqlDbInteractor(path_to_yaml)

# added value db_schema_version=3 to all test_db
def add_version_to_database_information():
    for path_to_sql_db in paths_to_sql_dbs_in_tests:
        conn = create_connection(path_to_sql_db)
        cursor = conn.cursor()
        cursor.execute(f"INSERT INTO ProteinGroupsInformation (ID,information) \
        VALUES ('db_schema_version', '3');")
        conn.commit()
        conn.close()


def print_db(path_to_db):
    conn = sqlite3.connect(path_to_db)
    for table in ['ProteinGroupsQuant', 'ProteinGroupsProteins', 'ProteinGroupsInformation', 'Samples', 'ProteinAccSpectra']:
        print(table)
        cursor = conn.cursor()
        print([row for row in cursor.execute(f"PRAGMA table_info({table});")])
        select_str = f"SELECT * from {table}"
        result_rows= cursor.execute(select_str)
        for row in result_rows:
            print(row)


def update_db(path_to_db, table, column_name, value, pgid, sample_id):
    conn = sqlite3.connect(path_to_db)
    cursor = conn.cursor()
    update_str = f"Update {table} SET {column_name}={value} WHERE id={pgid} AND sample_id={sample_id}"
    cursor.execute(update_str)
    conn.commit()
    conn.close()


def main():
    # DB version 0: pg_yaml -> convert to actual sql_db with: convert_yaml_to_db()
    # DB version 1: table  ProteinGroups ('id', 'proteins', 'quant', 'spectra', 'sample'), ProteinInformation (ID,  information)
    # DB version 2: table ProteinGroupsProteins('id', 'proteins'), ProteinGroupsQuant ('id', 'quant', 'spectra', 'sample')
    # ProteinInformation (ID,  information)
    # DB version 3: ProteinGroupsProteins('id', 'proteins'), ProteinGroupsQuant ('id', 'quant', 'spectra', 'sample_id')
    # Sample (sample_id, sample_name), ProteinInformation (ID,  information)
    # add_version_to_database_information()
    # print DB content with print_db(path_to_db)
    # convert pg_yaml to actual sql DB: convert_yaml_to_db(path_to_yaml)
    # update_all_test_databases()
    # path_to_db = "path/to/pgs/protein_groups_db.sql"
    # update_db(path_to_db, "ProteinGroupsQuant", 'quant', 10.0, 4, 0)
    update_all_test_databases()


if __name__ == "__main__":
    main()
