from __future__ import annotations

import pandas as pd

DEFAULT_COLUMN_MAPPING = {
    "date": ["date", "datetime", "timestamp", "trading_date"],
    "open": ["open", "o"],
    "high": ["high", "h"],
    "low": ["low", "l"],
    "close": ["close", "c"],
    "volume": ["volume", "v"],
}


def normalize_quotes(
    quotes: pd.DataFrame, column_mapping: dict[str, list[str]] | None = None
) -> pd.DataFrame:
    """
    Normalize the quotes DataFrame to ensure it has the required columns and format.

    Parameters
    ----------
    quotes : pd.DataFrame
        The input quotes DataFrame, which may have varying column names and formats.
    column_mapping : dict[str, list[str]] | None, optional
        A mapping of standard column names to possible column names in the input DataFrame.

    Returns
    -------
    pd.DataFrame
        A normalized DataFrame with standardized column names and formats.

    Raises
    ------
    ValueError
        If the input DataFrame does not contain the required columns or if the data cannot be normalized.
    """
    column_mapping = column_mapping or DEFAULT_COLUMN_MAPPING

    # Create a copy of the input DataFrame to avoid modifying the original data
    q = quotes.copy()
    q.columns = [col.lower().strip() for col in q.columns]  # Normalize column names to lowercase

    # Create a new DataFrame to hold the normalized data
    normalized_quotes = pd.DataFrame()

    # Iterate through the required columns and find the corresponding columns in the input DataFrame
    missing_cols = []
    for standard_col, possible_cols in column_mapping.items():
        for col in possible_cols:
            if col.lower().strip() in q.columns:
                normalized_quotes[standard_col] = q[col.lower().strip()]
                break
        else:
            missing_cols.append(standard_col)

    if missing_cols:
        raise ValueError(f"Missing required columns: {', '.join(missing_cols)}")

    if not isinstance(normalized_quotes.index, pd.DatetimeIndex):
        if "date" not in normalized_quotes.columns:
            raise ValueError(
                "Missing required datetime index. Please ensure the DataFrame has a datetime index or a column that can be converted to datetime."
            )
        normalized_quotes["date"] = pd.to_datetime(normalized_quotes["date"], errors="coerce")
        normalized_quotes.set_index("date", inplace=True)

    return normalized_quotes
