from selenium import webdriver
from selenium.webdriver.common.keys import Keys

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from selenium.common.exceptions import TimeoutException, NoSuchElementException

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from tabledef import *

from sqlalchemy.sql import func

# import os

UDEMY_EMAIL = "REPLACE_ME" # replace this with your access key, for example: UDEMY_EMAIL = "your_email_address@blah.com"
# UDEMY_EMAIL = os.environ.get('UDEMY_EMAIL_ADDRESS')
UDEMY_PASSWORD = "REPLACE_ME" # replace this with your access key, for example: UDEMY_PASSWORD = "ilovecplusplus"
# UDEMY_PASSWORD = os.environ.get('UDEMY_PASSWORD')
UDEMY_FOLDER_PATH = "REPLACE_ME" # replace this with your access key, for example: UDEMY_FOLDER_PATH = "C:/Users/YOUR_USERNAME/udemy-selenium/" for Windows, or "/Users/Your_Username/Desktop/udemy-selenium/"
# Windows users beware - change all \ to / in folder path
# UDEMY_FOLDER_PATH = os.environ.get('UDEMY_FOLDER_PATH')


# Initialise Database
engine = create_engine('sqlite:///courses.db')
Session = sessionmaker(bind=engine)
session = Session()

# first, let's do a quick check if there are even courses for us to enroll in itfp.
# there are 3 main criteria that we need to look at:
# 1. it should not be already enrolled - .filter(Course.remarks.isnot("enrolled"))
# 2. it should come from reddit - .filter(Course.post_date == "reddit")
# 3. it should be a 0-dollar discounted price course
# if the total number (count) of this query is zero, it means there are no such courses for us to enroll in.
# else, we proceed with the work process.
if session.query(Course).filter(Course.discounted_price == 0).filter(Course.remarks.isnot("enrolled")).filter(Course.post_date == "reddit").count() == 0:
    print("no courses to enroll from reddit. summarising and quitting...\n")

else:
    UDEMY_FOLDER_PATH = UDEMY_FOLDER_PATH + "chromedriver.exe" # + "chromedriver" for Mac users
    driver = webdriver.Chrome(UDEMY_FOLDER_PATH)
    driver.get("https://www.udemy.com/join/login-popup/")

    # when you assert something, you tell the program to test if the condition is true.
    # if it isn't (i.e. condition is false), trigger an error.
    assert "Udemy" in driver.title

    # we find the email field here.
    email_field = driver.find_element_by_id("id_email")
    email_field.clear() # we clear the field just in case
    email_field.send_keys(UDEMY_EMAIL)

    # we find the password field here.
    password_field = driver.find_element_by_id("id_password")
    password_field.clear() # we clear the field just in case
    password_field.send_keys(UDEMY_PASSWORD)

    # in Selenium, it is common to use the try-except block to try navigating to a new page.
    # if it isn't successful (usually a timeout error will be thrown, i.e. page taking too long to load),
    # the program will exit try and execute the code under except.
    try:
        # lazy way of logging in by hitting enter.
        # alternatively, you could find the "Sign In" button and use the click function.
        email_field.send_keys(Keys.RETURN)
    except:
        wait = WebDriverWait(driver, 10)
        # EC is the Expected Condition that we are looking out for.
        # in this case, we are looking out for when the URl changes to udemy.com,
        # thereby indicating that you have successfully logged in.
        # of course that it is not the only way to check if you have logged in successfully.
        home_page = wait.until(EC.url_to_be("https://www.udemy.com/"))


    # let's start enrolling!
    print("initialising enrollment for reddit...")

    # we create a query to check for all courses with discounted_price = 0  and remarks != enrolled
    for checkout_tr in session.query(Course).filter(Course.discounted_price == 0).filter(Course.remarks.isnot("enrolled")).filter(Course.post_date == "reddit"):
        checkout_url = checkout_tr.checkout_url

        try:
            driver.get(checkout_url)
        except:
            WebDriverWait(driver, 10).until(lambda driver: driver.current_url != checkout_url)

        if "/cart/success/" in driver.current_url:
            driver.implicitly_wait(10) # just in case
            # here we wait up to 15 seconds until the webdriver manages to find the Expected Condition of
            # the element with the class name of "success-lead__action" to be clickable
            element = WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.CLASS_NAME, "success-lead__action")))
            print("successfully enrolled!")

            # update db
            checkout_tr.remarks = "enrolled"
            session.commit()
            print("row", str(checkout_tr.id), "updated\n")


        # what happens if you have already enrolled in the course?
        # Udemy will redirect you to the overview page for that course instead.
        # the URL will look something like this 'udemy.com/the-course-i-already-enrolled-in/v1/overview'
        # we simply check if the url ends with overview. if so, we update our db that it is already enrolled.
        elif driver.current_url.endswith("/overview"):
            print("already enrolled. skipping to next...")

            # update db
            checkout_tr.remarks = "enrolled"
            session.commit()
            print("row", str(checkout_tr.id), "updated\n")

        # what if Udemy rediects you to a mysterious place?
        # let's just ignore it (warning: not a good practice, you should probably log this so that you will
        # know how to deal with such redirects in the future. but the chances here are slim so we ignore it.)
        else:
            print("an error has occured. skipping to next...")

    # Author's Remarks: you can remove "filter(Course.remarks.isnot("enrolled"))" to re-check all courses which are free.

    # finally, we quit the webdriver
    driver.close()
    print("all reddit enrollment completed.\n")
