"Class to create charts"

import numpy as np
import pandas as pd
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE

from services.stock_info.stock_performance import StockPerformance


class ChartCreator:
    "Class to create charts"

    def __init__(self) -> None:
        pass

    def get_stock_data(
        self, stock_ticker: str, duration: int, other_tickers: list = None
    ):
        "Get the stock data for the company"
        stock_perf_service = StockPerformance()
        all_tickers = [stock_ticker]
        if other_tickers is not None:
            all_tickers.extend(other_tickers)
            rebase_all = True

        stock_data = {}

        for ticker in all_tickers:
            data = stock_perf_service.get_stock_info(
                ticker=ticker, duration=duration, rebase=True
            )

            stock_data[ticker] = data

        stock_data_df = self._build_stock_data_df(
            stock_ticker, other_tickers, all_tickers, rebase_all, stock_data
        )

        return stock_data_df

    def _build_stock_data_df(
        self, stock_ticker, other_tickers, all_tickers, rebase_all, stock_data
    ):
        "Build the stock data dataframe"
        stock_data_df = pd.DataFrame(
            stock_data[stock_ticker],
            index=stock_data[stock_ticker]["date"],
        )
        stock_data_df = stock_data_df.drop(columns=["date", "rebased_close_price"])
        stock_data_df = stock_data_df.rename(columns={"close_price": stock_ticker})

        for ticker in other_tickers:
            new_df = pd.DataFrame(stock_data[ticker], index=stock_data[ticker]["date"])
            new_df = new_df.drop(columns=["date", "rebased_close_price"])
            stock_data_df = stock_data_df.join(new_df["close_price"])
            stock_data_df = stock_data_df.rename(columns={"close_price": ticker})

        if rebase_all:
            # rebase the stock prices in the dataframe
            # divide the stock prices by the first stock price
            for ticker in all_tickers:
                stock_data_df[ticker] = (
                    stock_data_df[ticker] / stock_data_df[ticker].iloc[0]
                )

        # convert date into a number value from 0 starting at 1/1/1900
        stock_data_df.index = stock_data_df.index.map(
            lambda x: ((pd.Timestamp(x) - pd.Timestamp("1900-01-01")).days)
        )

        return stock_data_df

    def add_line_chart(
        self, slide, top, left, width, height, data: pd.DataFrame, x_axis=None
    ):
        """
        Add charts to the slide
        placeholder for the chart
        data for the chart as a DF
        x_axis: the x-axis type
        """
        chart_data = CategoryChartData()

        # add the categories
        # if x-axis is a date, then add the date
        if x_axis == "date":
            chart_data.categories = list(
                data.index.map(
                    lambda x: pd.to_datetime(x, unit="D", origin="1899-12-30")
                )
            )
        else:
            chart_data.categories = list(data.index)

        for column in data.columns:
            data_to_graph = data[column].replace(np.nan, None)
            chart_data.add_series(column, data_to_graph)

        # add the chart object to the slide at the top and left with width and height
        chart_obj = slide.shapes.add_chart(
            XL_CHART_TYPE.LINE, left, top, width, height, chart_data
        )
        self._configure_chart(
            chart_obj, date_format="mmm-yyyy", number_format="_(0%;(0%)"
        )

    @staticmethod
    def _configure_chart(chart_obj, date_format="mmm-yyyy", number_format="_(0%;(0%)"):
        "Configure the chart"
        chart = chart_obj.chart
        chart.has_legend = True
        chart.has_title = False
        chart.has_axis = True
        chart.has_major_gridlines = False
        chart.has_minor_gridlines = False
        chart.has_data_table = False
        chart.has_up_down_bars = False
        chart.has_drop_lines = False
        chart.has_series_lines = False
        chart.has_markers = False

        category_axis = chart.category_axis
        category_axis.has_major_gridlines = False
        category_axis.has_minor_gridlines = False
        category_axis.has_title = False
        category_axis.tick_labels.number_format = date_format

        value_axis = chart.value_axis
        value_axis.has_major_gridlines = False
        value_axis.has_minor_gridlines = False
        value_axis.has_title = False
        value_axis.tick_labels.number_format = number_format
