"""
Module to load Microsoft Excel or CSV files as DataFrames.
"""

from inspect import stack
from logging import Logger, getLogger
from pathlib import Path
from typing import Annotated

from pandas import DataFrame, read_excel
from rich import print as rich_print
from typer import Argument, BadParameter, Context, Option

import genov.utils.typer.custom_types.custom_types
from genov.utils.typer.context_obj.context_obj import GContextObj

_logger: Logger = getLogger(__name__)


def df_load_xlsx(
    ctx_context: Context,
    path_file: Annotated[
        Path,
        Argument(
            help="The MS Excel file to import as a dataframe.",
            metavar="file",
            exists=True,
            file_okay=True,
            dir_okay=False,
            readable=True,
            resolve_path=True,
        ),
    ],
    str_alias: Annotated[
        str,
        Option(
            "--df_output",
            "-o",
            help="Alias for the loaded Date Frame to be persisted in context.",
            metavar="Df Alias",
            show_default="If not provided, defaulted to '_df'.",
            callback=GContextObj.check_alias_name_to_set,
        ),
    ] = "_df",
    lst_columns: Annotated[
        list | None,
        Option(
            "--columns",
            "-c",
            help="Columns labels to load, others will be discarded.",
            metavar="columns",
            show_default="By default, all columns are loaded.",
            parser=genov.utils.typer.custom_types.custom_types.CustomTypes.parse_custom_class,
        ),
    ] = None,
    dict_kwargs: Annotated[
        dict | None,
        Option(
            "--kwargs",
            "-k",
            help="Parameters for the underlying function pandas.read_excel.",
            metavar="kwargs",
            show_default="By default, no parameter provided.",
            parser=genov.utils.typer.custom_types.custom_types.CustomTypes.parse_custom_class,
        ),
    ] = None,
):
    """
    The command loads FILE from the file system in a DataFrame that is staged in context under alias DF ALIAS.
    In case only a subset of columns is to be loaded, these can be listed under COLUMNS, so useless columns are
    discarded.
    KWARGS can be used to provide any technical parameters to the underlying function "pandas.read_excel".
    """
    _logger.debug("Function '%s - %s' is called", stack()[0].filename, stack()[0].function)

    _obj_the_context_obj: GContextObj = ctx_context.obj

    # We load the MS Excel Spreadsheet
    if dict_kwargs:
        _df_the_data: DataFrame = read_excel(path_file, **dict_kwargs)
    else:
        _df_the_data: DataFrame = read_excel(path_file)

    rich_print(f"XLS-x file read, shape '{_df_the_data.shape}'.")

    # We only keep the listed columns, if such "listed columns" were even provided as parameter
    if lst_columns:
        # We check the listed columns are effectively in the data source
        _lst_the_inexistant_columns: list = list(set(lst_columns) - set(_df_the_data.columns))
        if len(_lst_the_inexistant_columns) > 0:
            _str_msg: str = (
                f"Selected columns '{', '.join(_lst_the_inexistant_columns)}' are not among existing ones "
                f"'{', '.join(_df_the_data.columns)}'."
            )
            raise BadParameter(_str_msg)

        # We filter out non-listed columns
        _df_the_data = _df_the_data[lst_columns]

        rich_print(f"Dataframe reduced, shape, shape '{_df_the_data.shape}'.")

    _obj_the_context_obj[str_alias] = _df_the_data
    rich_print(f"Dataframe staged in context under '{str_alias}'.")

    _logger.debug("Function '%s - %s' is returning", stack()[0].filename, stack()[0].function)
