#

from typing import List, Union, Any, NamedTuple, Tuple, Optional, Dict

import re
import logging
import datetime
import yfinance as yf  # type: ignore
import discord


class Price(NamedTuple):
    symbol: str
    date: str
    close: float


class Prices(NamedTuple):
    symbol: str
    created_at: datetime.datetime
    fiftyTwoWeeks: Tuple[str, str]
    day: Tuple[str, str]
    exchange: str
    prices: List[Price]


class PricesCache:
    map: Dict[str, Prices] = {}

    def maybe_query(self, symbol: str) -> Optional[Prices]:
        now = datetime.datetime.utcnow()
        if symbol in self.map:
            prices = self.map[symbol]
            age = now - prices.created_at
            if age < datetime.timedelta(minutes=10):
                return prices
        prices = query_stock(symbol)
        if prices:
            self.map[symbol] = prices
        return prices


def query_stock(symbol: str) -> Optional[Prices]:
    today = datetime.date.today()
    starting = today - datetime.timedelta(days=3)
    tomorrow = today + datetime.timedelta(days=1)
    data = yf.Ticker(symbol)

    history = data.history(
        period="1d",
        start=starting.strftime("%Y-%m-%d"),
        end=tomorrow.strftime("%Y-%m-%d"),
    )

    try:
        details = data.info

        yearHigh = details["fiftyTwoWeekHigh"]
        yearLow = details["fiftyTwoWeekLow"]
        exchange = details["exchange"]
        dayLow = details["dayLow"]
        dayHigh = details["dayHigh"]

        prices = []
        for key in history["Close"].keys():
            close = history["Close"][key]
            prices.append(Price(symbol=symbol, date=key, close=close))

        return Prices(
            created_at=datetime.datetime.utcnow(),
            symbol=symbol,
            exchange=exchange,
            prices=prices,
            day=(dayLow, dayHigh),
            fiftyTwoWeeks=(yearLow, yearHigh),
        )
    except KeyError:
        logging.exception("error")

    return None


def to_date_time_display(orig: Any) -> str:
    t = orig.time()
    if sum([t.hour, t.minute, t.second]) == 0:
        return orig.strftime("%m/%d")
    return str(orig)


prices_cache = PricesCache()


def summarize(symbol: str) -> str:
    prices = prices_cache.maybe_query(symbol.upper())
    if not prices:
        return "%s: Wut" % (symbol)

    yahoo_finance = "https://www.google.com/finance?q=%s" % (symbol,)
    google_finance = "https://www.google.com/finance?q=%s" % (symbol,)
    google_news = "https://news.google.com/search?q=%s" % (symbol,)

    last = prices.prices[-1]
    return "%s: [Google](%s) [Yahoo](%s) [News](%s): $%.2f (%s) 52w=(%s ... %s) 24h=(%s ... %s)" % (
        last.symbol,
        google_finance,
        yahoo_finance,
        google_news,
        last.close,
        to_date_time_display(last.date),
        prices.fiftyTwoWeeks[0],
        prices.fiftyTwoWeeks[1],
        prices.day[0],
        prices.day[1],
    )


def query_market(query: str) -> Optional[discord.Embed]:
    if not query:
        return None
    sanitized = query.strip()
    if not sanitized:
        return None
    symbols = sanitized.split(" ")
    if not symbols:
        return None
    detailed = [summarize(symbol) for symbol in symbols]
    return discord.Embed(title=query, description="\n".join(detailed), colour=0xFFFF00)


def stock_helper(query: str) -> discord.Embed:
    embed = query_market(query)
    if embed:
        return embed
    return discord.Embed(title="No symbols given", colour=0xFFFF00)


def debug(embed: discord.Embed) -> Tuple[str]:
    return (embed.title, embed.description)


if __name__ == "__main__":
    print(debug(stock_helper("")))
    print(debug(stock_helper("VTI")))
    print(debug(stock_helper("VTI")))
    print(debug(stock_helper("VTI FSELX")))
