import requests
import bs4
import re
import pandas as pd
from ftplib import FTP
from munch import munchify


import os
import shutil

if os.path.exists("cache") == False:
    os.mkdir("cache")
else:
    shutil.rmtree("cache")




def getLiveData(ticker, format="Dict"):
    page = None
    try:
        page = requests.get(f"https://finance.yahoo.com/quote/{ticker}")
    except:
        raise Exception(f"Ticker '{ticker}' does exist / cannot get page")

    soup = bs4.BeautifulSoup(page.content, 'html.parser')


    price = getPrice(soup)

    changes = getChange(soup)
    numChange = changes[0]
    percChange = changes[1]

    pe = getPEttm(soup)

    ranges = getRange(soup)
    low = ranges[0]
    high = ranges[1]

    open = getOpen(soup)
    prevClose = getPrevClose(soup)

    eps = getEPS(soup)

    mktCap = getMktCap(soup)

    volume = getVolume(soup)


    dataDict = {
        "Symbol": ticker,
        "Price": price,
        "Change": [{
            "change": numChange,
            "percentageChange": percChange
        }],
        "P/E": pe,
        "Ranges": [{
            "Low": low,
            "High": high
        }],
        "Open": open,
        "previousClose": prevClose,
        "EPS": eps,
        "marketCap": mktCap,
        "volume": volume
    }

    if format == "Dict":
        return dataDict
    if format == "DataFrame":
        return pd.DataFrame(dataDict)
    if format == "Object":
        return munchify(dataDict)

    raise Exception("Invalid Format Option")




def getPrice(soup):
    hits = soup.find(class_='Trsdu(0.3s) Fw(b) Fz(36px) Mb(-4px) D(ib)')

    if hits==None:
        return "N/A"

    if "," in hits.text:
        hits = hits.text.replace(",", "")
    else:
        hits = hits.text

    try:
        return float(hits)
    except:
        return "N/A"


def getChange(soup):
    hits = soup.find(class_='Trsdu(0.3s) Fw(500) Pstart(10px) Fz(24px) C($negativeColor)')

    if hits == None:
        hits = soup.find(class_='Trsdu(0.3s) Fw(500) Pstart(10px) Fz(24px) C($positiveColor)')

    if hits == None:
        return "N/A"

    try:
        numChange = hits.text.split(" ")[0].replace("+", "")
        percChange = re.search(r'\((.+)\)', hits.text).group(0).split("(")[1].split(")")[0]
    except:
        return "N/A"

    if "," in numChange:
        numChange = numChange.replace(",", "")

    return [float(numChange), percChange]

def getPEttm(soup):

    hits = soup.find(attrs={"data-reactid":149})

    if hits == None:
        return "N/A"

    val = hits.text.replace(",", "")

    try:
        return float(val)
    except:
        return val

def getRange(soup):
    hits = soup.find(attrs={"data-reactid": 117})
    if hits == None:
        return "N/A"

    split = hits.text.split("-")
    try:
        low = float(split[0])
        high = float(split[1])
    except:
        return "N/A"
    return [low, high]


def getOpen(soup):
    hits = soup.find(attrs={"data-test": "OPEN-value"})

    if hits == None:
        return "N/A"

    if "," in hits.text:
        hits = hits.text.replace(",", "")
        final = float(hits)


    try:
        final = float(hits)
    except:
        try:
            final = float(hits.text)
        except:
            return "N/A"
    return final

def getPrevClose(soup):
    hits = soup.find(attrs={"data-test": "PREV_CLOSE-value"})
    if hits == None:
        return "N/A"

    if "," in hits.text:
        hits = hits.text.replace(",", "")
        final = float(hits)
    else:
        final = float(hits.text)


    return final

def getEPS(soup):
    hits = soup.find(attrs={"data-test": "EPS_RATIO-value"})
    try:
        final = float(hits.text)
    except:
        return "N/A"
    return final

def getMktCap(soup):
    hits = soup.find(attrs={"data-test": "MARKET_CAP-value"})
    try:
        final = str(hits.text)
    except:
        return "N/A"
    if "B" in final:
        final = final.replace("B", "")
        final = float(final)
        final *= 1000000000
    elif "M" in final:
        final = final.replace("M", "")
        final = float(final)
        final *= 1000000


    return final

def getVolume(soup):
    hits = soup.find(attrs={"data-test": "TD_VOLUME-value"})
    if hits == None:
        return "N/A"

    final = hits.text.replace(",", "", -1)
    final = float(final)

    return final





def getIndex(index):
    if index == "S&P500":
        page = pd.read_html("https://en.wikipedia.org/wiki/List_of_S%26P_500_companies")
        return page[0]['Symbol'].tolist()

    if index == "NASDAQ":
        #ftp://ftp.nasdaqtrader.com/SymbolDirectory/nasdaqlisted.txt

        ftp = FTP('ftp.nasdaqtrader.com')
        ftp.login()
        ftp.cwd("SymbolDirectory")

        file = ftp.nlst()[9]

        ftp.retrbinary("RETR " + file, open("cache/nasdaq.txt", 'wb').write)

        df = pd.read_csv("cache/nasdaq.txt", sep="|")["Symbol"].tolist()
        return df

    if index == "NASDAQ.OTHER":
        ftp = FTP('ftp.nasdaqtrader.com')
        ftp.login()
        ftp.cwd("SymbolDirectory")
        file = ftp.nlst()[13]

        ftp.retrbinary("RETR " + file, open("cache/other.txt", 'wb').write)
        df = pd.read_csv("cache/other.txt", sep="|")["NASDAQ Symbol"].tolist()
        return df

    if index == "DOW":
        #https://en.wikipedia.org/wiki/Dow_Jones_Industrial_Average
        page = pd.read_html("https://finance.yahoo.com/quote/%5EDJI/components?p=%5EDJI")[0]["Symbol"].tolist()

        return page

    if index == "NYSE":
        ftp = FTP('ftp.nyse.com')
        ftp.login()
        ftp.cwd("NYSESymbolMapping")
        file = ftp.nlst()[0]

        ftp.retrbinary("RETR " + file, open("cache/nyse.txt", 'wb').write)

        df = pd.read_csv("cache/nyse.txt", sep="|").iloc[:, 0].tolist()
        return df


