import os
import glob
import psycopg2
import pandas as pd
from sql_queries import *

def process_song_file(cur, filepath):
    """ Connects to song json files and write them into song and artist db
    Keyword arguments:
    cur -- cursor to the database 
    filepath -- where the files are stored
    """
    # open song file
    df = pd.read_json(filepath, lines=True)

    # insert song record
    song_data = df[['song_id', 'title' ,'artist_id' ,'year' , 'duration']].get_values()[0]
    cur.execute(song_table_insert, song_data)
    
    # insert artist record
    artist_data  = df[['artist_id', 'artist_name' ,'artist_location' ,'artist_latitude' , 'artist_longitude']].values[0]

    cur.execute(artist_table_insert, artist_data)


def process_log_file(cur, filepath):
    """ connects to the log file and extracts time , user and songplay table
    Keyword arguments:
    cur -- cursor to the database 
    filepath -- where the files are stored
    """
    # open log file
    df = pd.read_json(filepath, lines=True)

    # filter by NextSong action
    df = df[df.page == 'NextSong']


    # convert timestamp column to datetime
    t  = pd.to_datetime(df['ts'], unit='ms')
    
    # insert time data records
    column_labels = ['timestamp', 'hour', 'day', 'week', 'month', 'year','weekday']

    time_data = pd.DataFrame(columns= column_labels , index = t.index)

    time_data['timestamp'] = t 
    time_data['hour'] = t.dt.hour
    time_data['day'] = t.dt.day
    time_data['week'] = t.dt.week 
    time_data['month'] = t.dt.month
    time_data['year'] = t.dt.year
    time_data['weekday'] = t.dt.day_name()

    time_df = time_data


    for i, row in time_df.iterrows():
        cur.execute(time_table_insert, list(row))

    # load user table
    user_df = df[['userId','firstName' , 'lastName' , 'gender' ,'level' ]]

    # insert user records
    for i, row in user_df.iterrows():
        cur.execute(user_table_insert, row)

    # insert songplay records
    for index, row in df.iterrows():
        
        # get songid and artistid from song and artist tables
        cur.execute(song_select, (row.song, row.artist, row.length))
        results = cur.fetchone()
        
        if results:
            songid, artistid = results
        else:
            songid, artistid = None, None

        # insert songplay record
        songplay_data =  [pd.to_datetime(row.ts, unit='ms'),row.userId, row.level, songid, artistid, 
                          row.sessionId ,row.location, row.userAgent]

        cur.execute(songplay_table_insert, songplay_data)


def process_data(cur, conn, filepath, func):
    """ 
    takes a function and runs the function on all the files in a directory. 
    
    Keyword arguments:
    cur -- cursor to the database 
    conn -- connection to database
    filepath -- where the files are stored
    func -- add the func to process the data through
    """
    # get all files matching extension from directory
    all_files = []
    for root, dirs, files in os.walk(filepath):
        files = glob.glob(os.path.join(root,'*.json'))
        for f in files :
            all_files.append(os.path.abspath(f))

    # get total number of files found
    num_files = len(all_files)
    print('{} files found in {}'.format(num_files, filepath))

    # iterate over files and process
    for i, datafile in enumerate(all_files, 1):
        func(cur, datafile)
        conn.commit()
        print('{}/{} files processed.'.format(i, num_files))


def main():
    """
    main function : connects to sparkifydb and creates a curssor , then process the data in folders
    song_data and log_data and closes the connection at the end.
    """
    conn = psycopg2.connect("host=127.0.0.1 dbname=sparkifydb user=student password=student")
    cur = conn.cursor()

    process_data(cur, conn, filepath='data/song_data', func=process_song_file)
    process_data(cur, conn, filepath='data/log_data', func=process_log_file)

    conn.close()


if __name__ == "__main__":
    main()