"""Custom Indicator Models"""
__docformat__ = "numpy"

import logging
from typing import Any, Tuple

import pandas as pd

from openbb_terminal.decorators import log_start_end
from openbb_terminal.rich_config import console

logger = logging.getLogger(__name__)


@log_start_end(log=logger)
def calculate_fib_levels(
    df_stock: pd.DataFrame,
    period: int = 120,
    open_date: Any = None,
    close_date: Any = None,
) -> Tuple[pd.DataFrame, pd.Timestamp, pd.Timestamp, float, float]:
    """Calculate Fibonacci levels

    Parameters
    ----------
    df_stock : pd.DataFrame
        Dataframe of prices
    period : int
        Days to look back for retracement
    open_date : Any
        Custom start date for retracement
    close_date : Any
        Custom end date for retracement

    Returns
    -------
    df : pd.DataFrame
        Dataframe of fib levels
    min_date: pd.Timestamp
        Date of min point
    max_date: pd.Timestamp:
        Date of max point
    min_pr: float
        Price at min point
    max_pr: float
        Price at max point
    """
    if open_date and close_date:
        if open_date not in df_stock.index:
            date0 = df_stock.index[df_stock.index.get_loc(open_date, method="nearest")]
            console.print(f"Start date not in df_stock.  Using nearest: {date0}")
        else:
            date0 = open_date
        if close_date not in df_stock.index:
            date1 = df_stock.index[df_stock.index.get_loc(close_date, method="nearest")]
            console.print(f"End date not in df_stock.  Using nearest: {date1}")
        else:
            date1 = close_date

        df_stock0 = df_stock.loc[date0, "Adj Close"]
        df_stock1 = df_stock.loc[date1, "Adj Close"]

        min_pr = min(df_stock0, df_stock1)
        max_pr = max(df_stock0, df_stock1)

        if min_pr == df_stock0:
            min_date = date0
            max_date = date1
        else:
            min_date = date1
            max_date = date0
    else:
        data_to_use = df_stock.iloc[period:]["Adj Close"]

        min_pr = data_to_use.min()
        min_date = data_to_use.idxmin()
        max_pr = data_to_use.max()
        max_date = data_to_use.idxmax()

    fib_levels = [0, 0.235, 0.382, 0.5, 0.618, 0.65, 1]
    price_dif = max_pr - min_pr

    levels = [round(max_pr - price_dif * f_lev, 2) for f_lev in fib_levels]

    df = pd.DataFrame()
    df["Level"] = fib_levels
    df["Level"] = df["Level"].apply(lambda x: str(x * 100) + "%")
    df["Price"] = levels

    return df, min_date, max_date, min_pr, max_pr

pandas.DataFrame