import numpy as np # helps with the math
import matplotlib.pyplot as plt # to plot error during training
from data.db_connect import Database
from data.stats_importer import Importer
from data.build_weather import get_weather, get_sun_and_moon_phase

# input data
inputs = np.array([[0, 0, 1, 0],
                   [0, 0, 1, 1],
                   [0, 0, 0, 0],
                   [1, 1, 0, 0],
                   [1, 1, 1, 1],
                   [1, 1, 0, 1]])
# output data
outputs = np.array([[0], [0], [0], [1], [1], [1]])

# create NeuralNetwork class
class NeuralNetwork:

    # intialize variables in class
    def __init__(self, inputs, outputs):
        self.inputs  = inputs
        self.outputs = outputs
        # initialize weights as .50 for simplicity
        self.weights = np.array([[.50], [.50], [.50], [0.50]])
        self.error_history = []
        self.epoch_list = []

    #activation function ==> S(x) = 1/1+e^(-x)
    def sigmoid(self, x, deriv=False):
        if deriv == True:
            return x * (1 - x)
        return 1 / (1 + np.exp(-x))

    # data will flow through the neural network.
    def feed_forward(self):
        self.hidden = self.sigmoid(np.dot(self.inputs, self.weights))

    # going backwards through the network to update weights
    def backpropagation(self):
        self.error  = self.outputs - self.hidden
        delta = self.error * self.sigmoid(self.hidden, deriv=True)
        self.weights += np.dot(self.inputs.T, delta)

    # train the neural net for 25,000 iterations
    def train(self, epochs=25000):
        for epoch in range(epochs):
            # flow forward and produce an output
            self.feed_forward()
            # go back though the network to make corrections based on the output
            self.backpropagation()    
            # keep track of the error history over each epoch
            self.error_history.append(np.average(np.abs(self.error)))
            self.epoch_list.append(epoch)

    # function to predict output on new and unseen input data                               
    def predict(self, new_input):
        prediction = self.sigmoid(np.dot(new_input, self.weights))
        return prediction

if __name__ == '__main__':
    build_db_path = "./data/sql/build_db.sql"
    fill_parks_path = "./data/sql/prefill_parks.sql"
    fill_teams_path = "./data/sql/prefill_teams.sql"

    db_file = "./database/baseball.db"
    db_conn = Database(db_file)

    db_conn.run_sql_file(build_db_path)
    db_conn.run_sql_file(fill_parks_path)
    db_conn.run_sql_file(fill_teams_path)

    imp = Importer(db_conn)
    imp.parse_all_data("./data/stats/to_import", "./data/stats/imported/")

    #we = Weather()
    #print(we.get_weather(39.26733000, -76.79831000, "20250706", 12))

    #park_data = db_conn.select("SELECT latitude, longitude FROM parks WHERE park_id = ?", ("ATL03",))
    #print(get_sun_and_moon_phase(park_data[0], park_data[1], "20250709"))
    #historic_weather = get_weather(park_data[0], park_data[1], game_stats["date"], hour)


else:
    # create neural network   
    NN = NeuralNetwork(inputs, outputs)
    # train neural network
    NN.train()

    # create two new examples to predict                                   
    example = np.array([[1, 1, 1, 0]])
    example_2 = np.array([[0, 0, 1, 1]])

    # print the predictions for both examples                                   
    print(NN.predict(example), ' - Correct: ', example[0][0])
    print(NN.predict(example_2), ' - Correct: ', example_2[0][0])

    # plot the error over the entire training duration
    plt.figure(figsize=(15,5))
    plt.plot(NN.epoch_list, NN.error_history)
    plt.xlabel('Epoch')
    plt.ylabel('Error')
    plt.savefig('plot.png')