import csv
import os
import requests
import json
import os, shutil
import datetime
def show_account(url):
    account = requests.get(url)
    account_body = json.loads(account.text)
    data = (account_body["response"])
    account_info = data["accounts"][0]
    print("Here is a summary of your spending in the account: "+account_info["name"])
    return account_info

#https://stackoverflow.com/questions/16870663/how-do-i-validate-a-date-string-format-in-python
def input_date(date_text):
    while True:
        date = input(date_text)
        print(date)
        try:
            datetime.datetime.strptime(date, '%Y-%m-%d')
            break
        except:
            print("Incorrect data format, should be YYYY-MM-DD")
    return date


def list_transactions(url):
    transactions = requests.get(url)
    transactions_body = json.loads(transactions.text)
    transaction_data = (transactions_body["response"]["transactions"])
    #data_keys =['id', 'description', 'date', 'normalizedDate', 'type', 'transactionType', 'amount', 'expenseAmount', 'accountId', 'accountName', 'tags', 'tagNames', 'status', 'isFutureDated']
    for d in transaction_data:
        return transaction_data

def include_category_key_words(category):
    included = return_list("db/"+category+".csv")
    return included

def return_list(filename):
    with open(filename, 'r') as f:
        reader = csv.reader(f)
        my_list = list(reader)
    return my_list[0]

def include_transactions(transactions,key_words):
    included_transactions = []

    for t in transactions:
        if key_words==["positive"] and -t["expenseAmount"]>0:
            included_transactions.append(t)
        elif key_words != ["other"]:
            for f in key_words:
                if(f.upper() in t["description"].upper()):
                    included_transactions.append(t)
    return included_transactions

def summarize(categories, transactions,budgets):
    #this creates a list of lists of key words for each category.
    #category_key_words[0] would be key words for the first category and so on so forth.
    category_key_words = []
    for c in categories:
        category_key_words.append(include_category_key_words(c))

    #this creates the list of list of dictionary transactions for each category
    category_payments = []
    for c in categories:
        category_payments.append(include_transactions(transactions,category_key_words[categories.index(c)])) #cycles through key words for that category

    # for everything else, the transactions is grouped to "other"
    for t in transactions:
        add_other = True
        for c in category_payments:
            if(t in c):
                add_other = False
        if(add_other):
            category_payments[1].append(t)
    print("Please note that transactions without key words are categorized as 'other' ")
    count = -1
    for c in reversed(category_payments):
        print("---------")
        print(categories[count].title()+":")
        print("---------")
        sum=0
        for i in c:
            sum = sum-i["expenseAmount"]
            print(i["normalizedDate"]+": "+i["description"]+": "+"(${0:,.2f})".format(float((-i["expenseAmount"]))))

        print("---------")
        print("---------")
        if(sum<0):
            print("The total amount spend on "+ categories[count].title() + " items is " +"(${0:,.2f})".format(float(sum)))
            if(sum<float(budgets[categories[count].lower()])):
                print("You are spending way too much in this category! Cut down!")
            else:
                print("You are meeting your goal when it comes to comes to "+categories[count]+". Feel free to spend more but don't go over the budget!")
            print()
        elif sum==0:
            print("You have no activity in the "+categories[count].title()+" category")
            print()
        else:
            print("Your income/refunds for the month is "+ "(${0:,.2f})".format(float(sum)))
            print()
        count+=-1

def write_list_to_file(filename, list):
    filepath = os.path.join(os.path.dirname(__file__), "db", filename)
    #print(f"OVERWRITING CONTENTS OF FILE: '{filepath}' \n ... WITH {len(products)} PRODUCTS")
    with open(filepath, "w") as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(list)

def reset():
    print("RESETTING DEFAULTS")

    folder = "db"
    for the_file in os.listdir(folder):
        file_path = os.path.join(folder, the_file)
        try:
            if os.path.isfile(file_path):
                os.unlink(file_path)
            #elif os.path.isdir(file_path): shutil.rmtree(file_path)
        except Exception as e:
            print(e)

    categories = return_list("db default/categories default.csv")
    write_list_to_file("categories.csv",categories)
    for c in categories:
        default_list = return_list("db default/"+c+" default.csv")
        write_list_to_file(c+".csv",default_list)

def set_budget(categories,budgets):
    for c in categories:
        budgets[c] = -float(input("What is your budget for "+ c))
    return budgets




#def group_transactions

#def matching_product(product_identifier,categories):
#    categories_list = [p for p in categories if p["id"] == product_identifier] #makes a list of p in categories that have product ID as ID. (will only have one item in this case)
#    return categories_list[0]

def run():
    #enter login information
    username = input("Please enter your email address: ")
    password = input("Please enter your password: ")
    
    #retrieve the token for your account's data
    base = "https://www.buxfer.com/api";
    login_url  = base + "/login?userid=" + username + "&password=" + password
    response = requests.get(login_url)
    response_body = json.loads(response.text)
    token = response_body["response"]["token"] # token is used to get information

    start_date = input_date("What start date would you like to analyze from? (YYYY-MM-DD)")
    end_date = input_date("What end date would you like to analyze to?(YYYY-MM-DD)")

    account_url =  base + "/accounts?token=" + token #url to get account(s)
    account = show_account(account_url)
    transactions_url =  base + "/transactions?token=" + token +"&startDate="+start_date+"&endDate="+end_date #url to get transactions
    transactions = list_transactions(transactions_url) #a list of all the transactions
    listed_data = [] #this is a list of all the transactions (which are each a dictionary)
    for t in transactions:
        listed_data.append({"Date":t["normalizedDate"],"Description":t["description"],"Amount":-t["expenseAmount"]})
    budgets = {}
    while True:
        try:
            categories = return_list("db/categories.csv")
        except:
            print("Your list of categories is missing. Let me fix that for you =]")
            reset()
            categories = return_list("db/categories.csv")

        # emptoy dictionaries evaluate to false. https://stackoverflow.com/questions/23177439/python-checking-if-a-dictionary-is-empty-doesnt-seem-to-work

        if bool(budgets)==False:
            for c in categories:
                budgets[c] = 100

        print("--------------------------------------------------")
        print("Here are the current categories of your expenses, along with key words that identify transactions to be in that category, and your budget")
        print("--------------------------------------------------")
        try:
            for c in categories:
                print(c.title()+":")
                print("Key words: "+ str(return_list("db/"+c+".csv")))
                if(c == "income"):
                    print("No budget. This should be as high as possible!")
                else:
                    print("Budget: "+"(${0:,.2f})".format(float(budgets[c])))
                print("--------------------------------------------------")
        except:
            print("You don't have a list for this category. Let me reset the defaults for you")
            reset()
            continue
        print("--------------------------------------------------")
        print()
        print(f"""
        Please select from the following:
            Operation | Description
            --------- | ------------------
            Category  | Adds a category to sort your expenses by
            Key Word  | Adds a key word to a specific category
            Budget    | Sets a budget for a category
            Summarize | Summarizes your expenses
            Reset     | Resets to default key_words and categories
            Finish    | Exit out of the program
            """)
        action = input("Please select an operation: ").title()
        if action not in ["Category","Key Word","Budget","Summarize","Reset","Finish"]:
            print("This is not one of the actions.")
            print("Please enter another action.")
            continue
        elif (action == "Summarize"):
            summarize(categories,transactions,budgets)
        elif action == "Category":
            new_category = input("Please input new category:  ").lower()
            if new_category in categories:
                print("This category already exists!")
                continue
            categories.append(new_category)
            write_list_to_file("categories.csv",categories)
            new_key_words=[]
            while True:
                key_word = input("What are some key_words for this category? Type done when finished.").lower()
                if key_word == "done":
                    break
                else:
                    new_key_words.append(key_word)
            write_list_to_file(new_category+".csv", new_key_words)

            budgets[new_category] = input("What is your budget for " + new_category+"? ")
        elif action == "Key Word":
            category = input("Which category would you like to add to?").lower()
            if(category not in categories):
                print("This category doesnt exist. Please create the category!")
                continue
            elif category == "other":
                print("There is no need to add a key_word to other as all remaining transactions will go into this group.")
                continue
            elif category == "income":
                print("There is no need to add a key_word to income as all positive amounts will go into this group.")
                continue
            print("Here are the current key words for "+category)
            current_key_words = return_list("db/"+category+".csv")
            print(current_key_words)
            while True:
                new_key_word = input("What key words would you like to add? (Type done when finished) ").lower()
                if new_key_word == "done":
                    break
                else:
                    current_key_words.append(new_key_word)
            print("Here are the current key words for "+category)
            print(current_key_words)
            write_list_to_file(category+".csv",current_key_words)
        elif action == "Reset":
            reset()
        elif action == "Budget":
            budgets = set_budget(categories,budgets)
        elif action == "Finish":
            print("Thank you for using our application!")
            exit()



#headers = ["id", "name", "aisle", "department", "price"]

#new_header_info = [header for header in headers if header != "id"]


    #elif action == "Category":
    #    print("CREATING A CATEGORY")
    #    new_header = input("Please input new category:  ").title()
    #    expense_headers.append(new_header)
    #    print("CREATING A NEW CATEGORY", new_header)




if __name__ == "__main__": ## this will run only when this program is invoked from the command line. So if we run the reset function, it wont run the whole thing
    run()

import csv
import os
import requests
import json
import os, shutil
import datetime
def show_account(url):
    account = requests.get(url)
    account_body = json.loads(account.text)
    data = (account_body["response"])
    account_info = data["accounts"][0]
    print("Here is a summary of your spending in the account: "+account_info["name"])
    return account_info

#https://stackoverflow.com/questions/16870663/how-do-i-validate-a-date-string-format-in-python
def input_date(date_text):
    while True:
        date = input(date_text)
        print(date)
        try:
            datetime.datetime.strptime(date, '%Y-%m-%d')
            break
        except:
            print("Incorrect data format, should be YYYY-MM-DD")
    return date


def list_transactions(url):
    transactions = requests.get(url)
    transactions_body = json.loads(transactions.text)
    transaction_data = (transactions_body["response"]["transactions"])
    #data_keys =['id', 'description', 'date', 'normalizedDate', 'type', 'transactionType', 'amount', 'expenseAmount', 'accountId', 'accountName', 'tags', 'tagNames', 'status', 'isFutureDated']
    for d in transaction_data:
        return transaction_data

def include_category_key_words(category):
    included = return_list("db/"+category+".csv")
    return included

def return_list(filename):
    with open(filename, 'r') as f:
        reader = csv.reader(f)
        my_list = list(reader)
    return my_list[0]

def include_transactions(transactions,key_words):
    included_transactions = []

    for t in transactions:
        if key_words==["positive"] and -t["expenseAmount"]>0:
            included_transactions.append(t)
        elif key_words != ["other"]:
            for f in key_words:
                if(f.upper() in t["description"].upper()):
                    included_transactions.append(t)
    return included_transactions

def summarize(categories, transactions,budgets):
    #this creates a list of lists of key words for each category.
    #category_key_words[0] would be key words for the first category and so on so forth.
    category_key_words = []
    for c in categories:
        category_key_words.append(include_category_key_words(c))

    #this creates the list of list of dictionary transactions for each category
    category_payments = []
    for c in categories:
        category_payments.append(include_transactions(transactions,category_key_words[categories.index(c)])) #cycles through key words for that category

    # for everything else, the transactions is grouped to "other"
    for t in transactions:
        add_other = True
        for c in category_payments:
            if(t in c):
                add_other = False
        if(add_other):
            category_payments[1].append(t)
    print("Please note that transactions without key words are categorized as 'other' ")
    count = -1
    for c in reversed(category_payments):
        print("---------")
        print(categories[count].title()+":")
        print("---------")
        sum=0
        for i in c:
            sum = sum-i["expenseAmount"]
            print(i["normalizedDate"]+": "+i["description"]+": "+"(${0:,.2f})".format(float((-i["expenseAmount"]))))

        print("---------")
        print("---------")
        if(sum<0):
            print("The total amount spend on "+ categories[count].title() + " items is " +"(${0:,.2f})".format(float(sum)))
            if(sum<float(budgets[categories[count].lower()])):
                print("You are spending way too much in this category! Cut down!")
            else:
                print("You are meeting your goal when it comes to comes to "+categories[count]+". Feel free to spend more but don't go over the budget!")
            print()
        elif sum==0:
            print("You have no activity in the "+categories[count].title()+" category")
            print()
        else:
            print("Your income/refunds for the month is "+ "(${0:,.2f})".format(float(sum)))
            print()
        count+=-1

def write_list_to_file(filename, list):
    filepath = os.path.join(os.path.dirname(__file__), "db", filename)
    #print(f"OVERWRITING CONTENTS OF FILE: '{filepath}' \n ... WITH {len(products)} PRODUCTS")
    with open(filepath, "w") as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(list)

def reset():
    print("RESETTING DEFAULTS")

    folder = "db"
    for the_file in os.listdir(folder):
        file_path = os.path.join(folder, the_file)
        try:
            if os.path.isfile(file_path):
                os.unlink(file_path)
            #elif os.path.isdir(file_path): shutil.rmtree(file_path)
        except Exception as e:
            print(e)

    categories = return_list("db default/categories default.csv")
    write_list_to_file("categories.csv",categories)
    for c in categories:
        default_list = return_list("db default/"+c+" default.csv")
        write_list_to_file(c+".csv",default_list)

def set_budget(categories,budgets):
    for c in categories:
        budgets[c] = -float(input("What is your budget for "+ c))
    return budgets




#def group_transactions

#def matching_product(product_identifier,categories):
#    categories_list = [p for p in categories if p["id"] == product_identifier] #makes a list of p in categories that have product ID as ID. (will only have one item in this case)
#    return categories_list[0]

def run():
    #enter login information
    username = input("Please enter your email address: ")
    password = input("Please enter your password: ")
    
    #retrieve the token for your account's data
    base = "https://www.buxfer.com/api";
    login_url  = base + "/login?userid=" + username + "&password=" + password
    response = requests.get(login_url)
    response_body = json.loads(response.text)
    token = response_body["response"]["token"] # token is used to get information

    start_date = input_date("What start date would you like to analyze from? (YYYY-MM-DD)")
    end_date = input_date("What end date would you like to analyze to?(YYYY-MM-DD)")

    account_url =  base + "/accounts?token=" + token #url to get account(s)
    account = show_account(account_url)
    transactions_url =  base + "/transactions?token=" + token +"&startDate="+start_date+"&endDate="+end_date #url to get transactions
    transactions = list_transactions(transactions_url) #a list of all the transactions
    listed_data = [] #this is a list of all the transactions (which are each a dictionary)
    for t in transactions:
        listed_data.append({"Date":t["normalizedDate"],"Description":t["description"],"Amount":-t["expenseAmount"]})
    budgets = {}
    while True:
        try:
            categories = return_list("db/categories.csv")
        except:
            print("Your list of categories is missing. Let me fix that for you =]")
            reset()
            categories = return_list("db/categories.csv")

        # emptoy dictionaries evaluate to false. https://stackoverflow.com/questions/23177439/python-checking-if-a-dictionary-is-empty-doesnt-seem-to-work

        if bool(budgets)==False:
            for c in categories:
                budgets[c] = 100

        print("--------------------------------------------------")
        print("Here are the current categories of your expenses, along with key words that identify transactions to be in that category, and your budget")
        print("--------------------------------------------------")
        try:
            for c in categories:
                print(c.title()+":")
                print("Key words: "+ str(return_list("db/"+c+".csv")))
                if(c == "income"):
                    print("No budget. This should be as high as possible!")
                else:
                    print("Budget: "+"(${0:,.2f})".format(float(budgets[c])))
                print("--------------------------------------------------")
        except:
            print("You don't have a list for this category. Let me reset the defaults for you")
            reset()
            continue
        print("--------------------------------------------------")
        print()
        print(f"""
        Please select from the following:
            Operation | Description
            --------- | ------------------
            Category  | Adds a category to sort your expenses by
            Key Word  | Adds a key word to a specific category
            Budget    | Sets a budget for a category
            Summarize | Summarizes your expenses
            Reset     | Resets to default key_words and categories
            Finish    | Exit out of the program
            """)
        action = input("Please select an operation: ").title()
        if action not in ["Category","Key Word","Budget","Summarize","Reset","Finish"]:
            print("This is not one of the actions.")
            print("Please enter another action.")
            continue
        elif (action == "Summarize"):
            summarize(categories,transactions,budgets)
        elif action == "Category":
            new_category = input("Please input new category:  ").lower()
            if new_category in categories:
                print("This category already exists!")
                continue
            categories.append(new_category)
            write_list_to_file("categories.csv",categories)
            new_key_words=[]
            while True:
                key_word = input("What are some key_words for this category? Type done when finished.").lower()
                if key_word == "done":
                    break
                else:
                    new_key_words.append(key_word)
            write_list_to_file(new_category+".csv", new_key_words)

            budgets[new_category] = input("What is your budget for " + new_category+"? ")
        elif action == "Key Word":
            category = input("Which category would you like to add to?").lower()
            if(category not in categories):
                print("This category doesnt exist. Please create the category!")
                continue
            elif category == "other":
                print("There is no need to add a key_word to other as all remaining transactions will go into this group.")
                continue
            elif category == "income":
                print("There is no need to add a key_word to income as all positive amounts will go into this group.")
                continue
            print("Here are the current key words for "+category)
            current_key_words = return_list("db/"+category+".csv")
            print(current_key_words)
            while True:
                new_key_word = input("What key words would you like to add? (Type done when finished) ").lower()
                if new_key_word == "done":
                    break
                else:
                    current_key_words.append(new_key_word)
            print("Here are the current key words for "+category)
            print(current_key_words)
            write_list_to_file(category+".csv",current_key_words)
        elif action == "Reset":
            reset()
        elif action == "Budget":
            budgets = set_budget(categories,budgets)
        elif action == "Finish":
            print("Thank you for using our application!")
            exit()



#headers = ["id", "name", "aisle", "department", "price"]

#new_header_info = [header for header in headers if header != "id"]


    #elif action == "Category":
    #    print("CREATING A CATEGORY")
    #    new_header = input("Please input new category:  ").title()
    #    expense_headers.append(new_header)
    #    print("CREATING A NEW CATEGORY", new_header)




if __name__ == "__main__": ## this will run only when this program is invoked from the command line. So if we run the reset function, it wont run the whole thing
    run()

#https://stackoverflow.com/questions/16870663/how-do-i-validate-a-date-string-format-in-python #data_keys =['id', 'description', 'date', 'normalizedDate', 'type', 'transactionType', 'amount', 'expenseAmount', 'accountId', 'accountName', 'tags', 'tagNames', 'status', 'isFutureDated'] #this creates a list of lists of key words for each category. #category_key_words[0] would be key words for the first category and so on so forth. #this creates the list of list of dictionary transactions for each category #cycles through key words for that category # for everything else, the transactions is grouped to "other" #print(f"OVERWRITING CONTENTS OF FILE: '{filepath}' \n ... WITH {len(products)} PRODUCTS") #elif os.path.isdir(file_path): shutil.rmtree(file_path) #def group_transactions #def matching_product(product_identifier,categories): #    categories_list = [p for p in categories if p["id"] == product_identifier] #makes a list of p in categories that have product ID as ID. (will only have one item in this case) #    return categories_list[0] #enter login information #retrieve the token for your account's data # token is used to get information #url to get account(s) #url to get transactions #a list of all the transactions #this is a list of all the transactions (which are each a dictionary) # emptoy dictionaries evaluate to false. https://stackoverflow.com/questions/23177439/python-checking-if-a-dictionary-is-empty-doesnt-seem-to-work Please select from the following:             Operation | Description             --------- | ------------------             Category  | Adds a category to sort your expenses by             Key Word  | Adds a key word to a specific category             Budget    | Sets a budget for a category             Summarize | Summarizes your expenses             Reset     | Resets to default key_words and categories             Finish    | Exit out of the program #headers = ["id", "name", "aisle", "department", "price"] #new_header_info = [header for header in headers if header != "id"] #elif action == "Category": #    print("CREATING A CATEGORY") #    new_header = input("Please input new category:  ").title() #    expense_headers.append(new_header) #    print("CREATING A NEW CATEGORY", new_header) ## this will run only when this program is invoked from the command line. So if we run the reset function, it wont run the whole thing